您的位置:首页 > 编程语言

常见排序算法代码整理

2016-11-02 17:03 260 查看
排序算法的稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。

1、交换排序

(1)冒泡排序:

[java] view
plain copy

public void BubbleSort(int[] x)  

{  

    for(int i=0;i<x.length-1;i++)          //若数组长度为n,则执行n-1次“冒泡”即可(每次可找出剩余元素的最大值,剩下的一个为最小值)  

    {  

        for(int j=0;j<x.length-i-1;j++)    //执行第i次“冒泡的时候”在数组尾部已经有i-1个排好序的“最大值”  

        {  

            if(x[j]>x[j+1])  

                swap(x,j,j+1);  

        }  

    }  

}  

public void swap(int[] x,int i,int j)  

{  

    int t=x[i];  

    x[i]=x[j];  

    x[j]=t;  

}  

时间复杂度:O(n^2)

空间复杂度:O(1)

稳定性:稳定

(2)快速排序:

[java] view
plain copy

public void Quicksort(int[] x)  

{  

    HelperOfQuicksort(x,0,x.length-1);  

}  

public void HelperOfQuicksort(int[] x,int low,int high)  

{  

    if(low<high)  

    {  

        int mid=getMiddleIndex(x,low,high);    //mid左面的部分都小于等于x[mid],mid右面的部分都大于等于x[mid]  

        HelperOfQuicksort(x,low,mid-1);          

        HelperOfQuicksort(x,mid+1,high);  

    }  

}  

public int getMiddleIndex(int[] x,int low,int high)  

{  

    int tmp=x[low];                             //选当前无序部分的第一个元素做标兵  

    while(low<high)  

    {  

        while(low<high&&x[high]>=tmp)  

            high--;  

        x[low]=x[high];                         //x[high]是本次循环找到的小于tmp的值  

        while(low<high&&x[low]<=tmp)  

            low++;  

        x[high]=x[low];                         //x[low]是本次循环找到的大于tmp的值  

    }  

    x[low]=tmp;                                 //循环结束后,对应本次函数处理的部分数组(假设从a到b),a到low-1为小于等于tmp的部分,low+1到b为大于等于tmp的部分  

    return low;                                 //此时low=high  

}  

时间复杂度:O(n^logn)

空间复杂度:O(n^logn)

稳定性:不稳定

2、插入排序

(1)直接插入排序:

[java] view
plain copy

public void StraightInsertionSort(int[] x)  

{  

    if(x.length==1)  

        return ;  

    for(int i=1;i<x.length;i++)        //将数组中的1到x.length-1位置的元素分别插入前面排好序的部分的相应位置(起始的排好序的部分是x[0])  

    {  

        int cur=x[i];                  //当前待插入元素  

        int m=i-1;                     //从当前元素的前一个元素开始比较  

        for(;m>=0&&x[m]>cur;m--)       //前面的元素如果>当前待插入元素则将此元素在数组中后移一个位置  

            x[m+1]=x[m];  

        x[m+1]=cur;
                   //跳出循环时,证明m是小于待插入元素的位置(或者m=-1),将待插入元素插在m+1的位置  

    }  

}  

时间复杂度:O(n^2)

空间复杂度:O(1)

稳定性:稳定

(2)希尔排序:

[java] view
plain copy

public void ShellSort(int[] x)  

{  

    int gap=x.length/2;  

    while(gap>=1)                                          //最外层循环控制步长  

    {  

        for(int i=0;i<gap;i++)                         //若gap=3,则有三组子序列需要分别进行直接插入排序  

        {  

            for(int j=i+gap;j<x.length;j+=gap)     //对每一组子序列进行单独进行直接插入排序  

            {  

                int cur=x[j];  

                int index=j-gap;  

                for(;index>=0&&x[index]>cur;index-=gap)  

                    x[index+gap]=x[index];  

                x[index+gap]=cur;  

            }  

        }  

        gap/=2;  

    }  

}

时间复杂度:O(n^1.25)到O((1.6n)^1.25)(经验公式)

空间复杂度:O(1)

稳定性:不稳定

3、选择排序

(1)简单选择排序:

[java] view
plain copy

public void SimpleSelectionSort(int[] x)  

{  

    for(int i=0;i<=x.length-2;i++)    //每次找到当前数组剩余元素中的最小值,和剩余部分元素的首元素交换。五个元素交换四次即可。  

    {                                 //i指向当前未排序部分(即剩余部分)的首元素  

        int curMin=Integer.MAX_VALUE;  

        int index=-1;  

        for(int j=i;j<x.length;j++)   //从i开始直到数组最后找到最小值和它的index  

        {  

            if(x[j]<curMin)  

            {  

                index=j;  

                curMin=x[j];  

            }  

        }  

        swap(x,i,index);  

    }  

}  

public void swap(int[] x,int i,int j)  

{  

    int t=x[i];  

    x[i]=x[j];  

    x[j]=t;  

}  

时间复杂度:O(n^2)

空间复杂度:O(1)

稳定性:不稳定([2,2,1],循环首次执行之后1与首元素,即第一个2交换,变成[1,2,2]。第一个二跑到了最后,在原来第二个2之后)

(2)堆排序

[java] view
plain copy

public void Heapsort(int[] x)  

{  

     //每次将0到i的元素建堆(只是把数组想作堆结构)后,找到堆顶的元素(即首元素)与i位置的元素交换。即0到i为当前无序部分,i之后都是有序部分  

    for(int i=x.length-1;i>=1;i--)    

    {  

        BuildHeap(x,i);  

        swap(x,0,i);  

    }  

}  

public void BuildHeap(int[] x,int LastIndex)  

{  

    int k=-1;  

     //从LastIndex到1位置的元素分别找到它们的父结点,如果父结点的值比它的全部子节点的值都大,则不变;否则将父结点的值与子节点中的较大值互换(可能存在当前父结点没有右子节点的情况)  

    for(int i=LastIndex;i>=1;i--)    

    {  

        int curParentNode=(i-1)/2;    //(当前结点下标-1)/2即为它的父结点的下标,无论左右结点都适用  

        //目前的k指向上次循环处理过的父结点,如果k与curParentNode相同,则证明当前的父结点已经处理过了(即它的值肯定大于等于它的子节点的值)  

        if(curParentNode==k)          

            continue;  

        k=curParentNode;             //若当前的父结点没有处理过,则更新k  

        int biggerSonNode=-1;        //biggerSonNode指向当前父结点的子节点中值较大的子节点  

        if(k*2+2<=LastIndex)         //k*2+2指向当前父结点的右结点,如果它大于LastIndex,则证明当前父结点没有右子结点  

            biggerSonNode=x[k*2+1]>=x[k*2+2]?(k*2+1):(k*2+2);  

        else  

            biggerSonNode=k*2+1;  

        if(x[biggerSonNode]>x[k])    //如子节点中较大值大于父结点的值,则交换,保证每一个父结点的值都大于它的所有子节点,最终保证堆顶的元素值最大  

            swap(x,biggerSonNode,k);  

    }  

}  

public void swap(int[] x,int i,int j)  

{  

    int t=x[i];  

    x[i]=x[j];  

    x[j]=t;  

}  

时间复杂度:O(n*logn)

空间复杂度:O(1)

稳定性:不稳定

4、归并排序

[java] view
plain copy

public void MergeSort(int[] x)  

{  

    HelperSort(x,0,x.length-1);  

}  

public void HelperSort(int[] x,int start,int end)  //将当前待处理的部分继续划分为两部分  

{  

    if(start>=end)  

        return;  

    int mid=(start+end)/2;  

    int start1=start;                       //第一个部分的起始下标  

    int end1=mid;                           //第一个部分的终止下标  

    int start2=mid+1;                       //第二个部分的起始下标  

    int end2=end;                           //第二个部分的终止下标  

    HelperSort(x,start1,end1);  

    HelperSort(x,start2,end2);  

    merge(x,start1,end1,start2,end2);       //将划分好的两部分归并。每次归并的两个部分分别都已经是有序的了。  

}  

public void merge(int[] x,int FirStart,int FirEnd,int SecStart,int SecEnd)  

{  

    int[] temp=new int[SecEnd-FirStart+1];   //临时生成一个新的数组用来存储归并之后的两个部分的合成数组  

    int tempIndex=0;                           

    int first=FirStart;                      //指向第一个部分的首个元素  

    int second=SecStart;                     //指向第二个部分的首个元素  

    while(first<=FirEnd&&second<=SecEnd)     //直到遍历到某个部分的最后一个元素  

    {  

        if(x[first]<=x[second])          //first和second始终指向当前第一(二)个部分剩余元素的最小值  

        {  

            temp[tempIndex]=x[first];  

            tempIndex++;  

            first++;  

        }  

        else  

        {  

            temp[tempIndex]=x[second];  

            tempIndex++;  

            second++;  

        }  

    }  

    while(first<=FirEnd)                     //若第一个部分还有剩余没有并入新的临时数组,则直接并入  

        temp[tempIndex++]=x[first++];  

    while(second<=SecEnd)                    //若第二个部分还有剩余没有并入新的临时数组,则直接并入  

        temp[tempIndex++]=x[second++];  

    for(int i=0;i<tempIndex;i++)        //将并好的有序数组写入原始数组的相应位置(从第一部分的起始到第二部分的结束(因为这两部分在原数组处在相邻位置))  

        x[FirStart+i]=temp[i];  

      

}  

时间复杂度:O(n*logn)

空间复杂度:O(n)

稳定性:稳定

5、基数排序

[java] view
plain copy

public void RadixSort(int[] x)  

{  

    int max=Integer.MIN_VALUE;  

    for(int i=0;i<x.length;i++)                 //找到数组中的最大值  

    {  

        if(x[i]>max)  

            max=x[i];  

    }  

    int maxbit=0;  

    while(max>0)                                //找到最大位数  

    {  

        max/=10;  

        maxbit++;  

    }  

    int radix=10;                               //0~9共10个桶  

    ArrayList<Queue> list=new ArrayList<>();    //用来存储桶的list。list.get(1)存储着桶1  

    for(int i=0;i<radix;i++)  

    {  

        Queue<Integer> q=new LinkedList<>();  

        list.add(q);  

    }  

      

//x中最初存储[5,1,3,7,23,72,7].确认最大位数为十位,故只需整体入桶两次即可(先按照个位后按照十位) 

//首先按照个位入桶  

//桶1:1  

//桶2:72  

//桶3:3,23  

//桶5:5  

//桶7:7,7  

//其余的桶为空  

//按桶从小到大,同一个桶从左到右的顺序将全部元素放回数组x中(由于使用的是队列,每次头元素入x的同时就会清空桶(队列)中的头元素)  

//x为[1,72,3,23,5,7,7],再按照十位入桶  

//桶0:1,3,5,7,7  

//桶2:23  

//桶7:72  

//其余的桶为空  

//按桶从小到大,同一个桶从左到右的顺序将全部元素放回数组x中  

//x为[1,3,5,7,7,23,72],完毕  

  

    int dividend=1;  

    for(int i=0;i<maxbit;i++)                       //从低位到高位分别处理  

    {  

        for(int j1=0;j1<x.length;j1++)          //将所有元素按照当前检测位的数字大小入桶  

        {  

            int index=(x[j1]/dividend)%radix;  

            list.get(index).offer(x[j1]);  

        }  

        dividend*=10;  

        int m=0;  

        for(int j2=0;j2<radix;j2++)             //按桶从小到大,同一个桶从左到右的顺序将全部元素放回数组x中  

        {  

            while(list.get(j2).size()!=0)  

            {  

                x[m]=(int) list.get(j2).poll();  

                m++;  

            }  

        }  

    }  

}  

时间复杂度:O(d*n)     d为长度(对应代码中maxbit),n为数组长度

空间复杂度:O(n)

稳定性:稳定
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: