常见排序算法代码整理

来源:互联网 发布:gamemaker 不需要编程 编辑:程序博客网 时间:2024/05/22 15:25

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


1、交换排序


(1)冒泡排序:

[java] view plain copy
  1. public void BubbleSort(int[] x)  
  2. {  
  3.     for(int i=0;i<x.length-1;i++)          //若数组长度为n,则执行n-1次“冒泡”即可(每次可找出剩余元素的最大值,剩下的一个为最小值)  
  4.     {  
  5.         for(int j=0;j<x.length-i-1;j++)    //执行第i次“冒泡的时候”在数组尾部已经有i-1个排好序的“最大值”  
  6.         {  
  7.             if(x[j]>x[j+1])  
  8.                 swap(x,j,j+1);  
  9.         }  
  10.     }  
  11. }  
  12. public void swap(int[] x,int i,int j)  
  13. {  
  14.     int t=x[i];  
  15.     x[i]=x[j];  
  16.     x[j]=t;  
  17. }  

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

空间复杂度:O(1)

稳定性:稳定


(2)快速排序:

[java] view plain copy
  1. public void Quicksort(int[] x)  
  2. {  
  3.     HelperOfQuicksort(x,0,x.length-1);  
  4. }  
  5. public void HelperOfQuicksort(int[] x,int low,int high)  
  6. {  
  7.     if(low<high)  
  8.     {  
  9.         int mid=getMiddleIndex(x,low,high);    //mid左面的部分都小于等于x[mid],mid右面的部分都大于等于x[mid]  
  10.         HelperOfQuicksort(x,low,mid-1);          
  11.         HelperOfQuicksort(x,mid+1,high);  
  12.     }  
  13. }  
  14. public int getMiddleIndex(int[] x,int low,int high)  
  15. {  
  16.     int tmp=x[low];                             //选当前无序部分的第一个元素做标兵  
  17.     while(low<high)  
  18.     {  
  19.         while(low<high&&x[high]>=tmp)  
  20.             high--;  
  21.         x[low]=x[high];                         //x[high]是本次循环找到的小于tmp的值  
  22.         while(low<high&&x[low]<=tmp)  
  23.             low++;  
  24.         x[high]=x[low];                         //x[low]是本次循环找到的大于tmp的值  
  25.     }  
  26.     x[low]=tmp;                                 //循环结束后,对应本次函数处理的部分数组(假设从a到b),a到low-1为小于等于tmp的部分,low+1到b为大于等于tmp的部分  
  27.     return low;                                 //此时low=high  
  28. }  

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

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

稳定性:不稳定


2、插入排序


(1)直接插入排序:

[java] view plain copy
  1. public void StraightInsertionSort(int[] x)  
  2. {  
  3.     if(x.length==1)  
  4.         return ;  
  5.     for(int i=1;i<x.length;i++)        //将数组中的1到x.length-1位置的元素分别插入前面排好序的部分的相应位置(起始的排好序的部分是x[0])  
  6.     {  
  7.         int cur=x[i];                  //当前待插入元素  
  8.         int m=i-1;                     //从当前元素的前一个元素开始比较  
  9.         for(;m>=0&&x[m]>cur;m--)       //前面的元素如果>当前待插入元素则将此元素在数组中后移一个位置  
  10.             x[m+1]=x[m];  
  11.         x[m+1]=cur;                    //跳出循环时,证明m是小于待插入元素的位置(或者m=-1),将待插入元素插在m+1的位置  
  12.     }  
  13. }  

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

空间复杂度:O(1)

稳定性:稳定


(2)希尔排序:

[java] view plain copy
  1. public void ShellSort(int[] x)  
  2. {  
  3.     int gap=x.length/2;  
  4.     while(gap>=1)                                          //最外层循环控制步长  
  5.     {  
  6.         for(int i=0;i<gap;i++)                         //若gap=3,则有三组子序列需要分别进行直接插入排序  
  7.         {  
  8.             for(int j=i+gap;j<x.length;j+=gap)     //对每一组子序列进行单独进行直接插入排序  
  9.             {  
  10.                 int cur=x[j];  
  11.                 int index=j-gap;  
  12.                 for(;index>=0&&x[index]>cur;index-=gap)  
  13.                     x[index+gap]=x[index];  
  14.                 x[index+gap]=cur;  
  15.             }  
  16.         }  
  17.         gap/=2;  
  18.     }  
  19. }

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

空间复杂度:O(1)

稳定性:不稳定


3、选择排序


(1)简单选择排序:

[java] view plain copy
  1. public void SimpleSelectionSort(int[] x)  
  2. {  
  3.     for(int i=0;i<=x.length-2;i++)    //每次找到当前数组剩余元素中的最小值,和剩余部分元素的首元素交换。五个元素交换四次即可。  
  4.     {                                 //i指向当前未排序部分(即剩余部分)的首元素  
  5.         int curMin=Integer.MAX_VALUE;  
  6.         int index=-1;  
  7.         for(int j=i;j<x.length;j++)   //从i开始直到数组最后找到最小值和它的index  
  8.         {  
  9.             if(x[j]<curMin)  
  10.             {  
  11.                 index=j;  
  12.                 curMin=x[j];  
  13.             }  
  14.         }  
  15.         swap(x,i,index);  
  16.     }  
  17. }  
  18. public void swap(int[] x,int i,int j)  
  19. {  
  20.     int t=x[i];  
  21.     x[i]=x[j];  
  22.     x[j]=t;  
  23. }  

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

空间复杂度:O(1)

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


(2)堆排序

[java] view plain copy
  1. public void Heapsort(int[] x)  
  2. {  
  3.      //每次将0到i的元素建堆(只是把数组想作堆结构)后,找到堆顶的元素(即首元素)与i位置的元素交换。即0到i为当前无序部分,i之后都是有序部分  
  4.     for(int i=x.length-1;i>=1;i--)    
  5.     {  
  6.         BuildHeap(x,i);  
  7.         swap(x,0,i);  
  8.     }  
  9. }  
  10. public void BuildHeap(int[] x,int LastIndex)  
  11. {  
  12.     int k=-1;  
  13.      //从LastIndex到1位置的元素分别找到它们的父结点,如果父结点的值比它的全部子节点的值都大,则不变;否则将父结点的值与子节点中的较大值互换(可能存在当前父结点没有右子节点的情况)  
  14.     for(int i=LastIndex;i>=1;i--)    
  15.     {  
  16.         int curParentNode=(i-1)/2;    //(当前结点下标-1)/2即为它的父结点的下标,无论左右结点都适用  
  17.         //目前的k指向上次循环处理过的父结点,如果k与curParentNode相同,则证明当前的父结点已经处理过了(即它的值肯定大于等于它的子节点的值)  
  18.         if(curParentNode==k)          
  19.             continue;  
  20.         k=curParentNode;             //若当前的父结点没有处理过,则更新k  
  21.         int biggerSonNode=-1;        //biggerSonNode指向当前父结点的子节点中值较大的子节点  
  22.         if(k*2+2<=LastIndex)         //k*2+2指向当前父结点的右结点,如果它大于LastIndex,则证明当前父结点没有右子结点  
  23.             biggerSonNode=x[k*2+1]>=x[k*2+2]?(k*2+1):(k*2+2);  
  24.         else  
  25.             biggerSonNode=k*2+1;  
  26.         if(x[biggerSonNode]>x[k])    //如子节点中较大值大于父结点的值,则交换,保证每一个父结点的值都大于它的所有子节点,最终保证堆顶的元素值最大  
  27.             swap(x,biggerSonNode,k);  
  28.     }  
  29. }  
  30. public void swap(int[] x,int i,int j)  
  31. {  
  32.     int t=x[i];  
  33.     x[i]=x[j];  
  34.     x[j]=t;  
  35. }  

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

空间复杂度:O(1)

稳定性:不稳定


4、归并排序

[java] view plain copy
  1. public void MergeSort(int[] x)  
  2. {  
  3.     HelperSort(x,0,x.length-1);  
  4. }  
  5. public void HelperSort(int[] x,int start,int end)  //将当前待处理的部分继续划分为两部分  
  6. {  
  7.     if(start>=end)  
  8.         return;  
  9.     int mid=(start+end)/2;  
  10.     int start1=start;                       //第一个部分的起始下标  
  11.     int end1=mid;                           //第一个部分的终止下标  
  12.     int start2=mid+1;                       //第二个部分的起始下标  
  13.     int end2=end;                           //第二个部分的终止下标  
  14.     HelperSort(x,start1,end1);  
  15.     HelperSort(x,start2,end2);  
  16.     merge(x,start1,end1,start2,end2);       //将划分好的两部分归并。每次归并的两个部分分别都已经是有序的了。  
  17. }  
  18. public void merge(int[] x,int FirStart,int FirEnd,int SecStart,int SecEnd)  
  19. {  
  20.     int[] temp=new int[SecEnd-FirStart+1];   //临时生成一个新的数组用来存储归并之后的两个部分的合成数组  
  21.     int tempIndex=0;                           
  22.     int first=FirStart;                      //指向第一个部分的首个元素  
  23.     int second=SecStart;                     //指向第二个部分的首个元素  
  24.     while(first<=FirEnd&&second<=SecEnd)     //直到遍历到某个部分的最后一个元素  
  25.     {  
  26.         if(x[first]<=x[second])          //first和second始终指向当前第一(二)个部分剩余元素的最小值  
  27.         {  
  28.             temp[tempIndex]=x[first];  
  29.             tempIndex++;  
  30.             first++;  
  31.         }  
  32.         else  
  33.         {  
  34.             temp[tempIndex]=x[second];  
  35.             tempIndex++;  
  36.             second++;  
  37.         }  
  38.     }  
  39.     while(first<=FirEnd)                     //若第一个部分还有剩余没有并入新的临时数组,则直接并入  
  40.         temp[tempIndex++]=x[first++];  
  41.     while(second<=SecEnd)                    //若第二个部分还有剩余没有并入新的临时数组,则直接并入  
  42.         temp[tempIndex++]=x[second++];  
  43.     for(int i=0;i<tempIndex;i++)        //将并好的有序数组写入原始数组的相应位置(从第一部分的起始到第二部分的结束(因为这两部分在原数组处在相邻位置))  
  44.         x[FirStart+i]=temp[i];  
  45.       
  46. }  

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

空间复杂度:O(n)

稳定性:稳定


5、基数排序

[java] view plain copy
  1. public void RadixSort(int[] x)  
  2. {  
  3.     int max=Integer.MIN_VALUE;  
  4.     for(int i=0;i<x.length;i++)                 //找到数组中的最大值  
  5.     {  
  6.         if(x[i]>max)  
  7.             max=x[i];  
  8.     }  
  9.     int maxbit=0;  
  10.     while(max>0)                                //找到最大位数  
  11.     {  
  12.         max/=10;  
  13.         maxbit++;  
  14.     }  
  15.     int radix=10;                               //0~9共10个桶  
  16.     ArrayList<Queue> list=new ArrayList<>();    //用来存储桶的list。list.get(1)存储着桶1  
  17.     for(int i=0;i<radix;i++)  
  18.     {  
  19.         Queue<Integer> q=new LinkedList<>();  
  20.         list.add(q);  
  21.     }  
  22.       
  23. //x中最初存储[5,1,3,7,23,72,7].确认最大位数为十位,故只需整体入桶两次即可(先按照个位后按照十位) 
  24. //首先按照个位入桶  
  25. //桶1:1  
  26. //桶2:72  
  27. //桶3:3,23  
  28. //桶5:5  
  29. //桶7:7,7  
  30. //其余的桶为空  
  31. //按桶从小到大,同一个桶从左到右的顺序将全部元素放回数组x中(由于使用的是队列,每次头元素入x的同时就会清空桶(队列)中的头元素)  
  32. //x为[1,72,3,23,5,7,7],再按照十位入桶  
  33. //桶0:1,3,5,7,7  
  34. //桶2:23  
  35. //桶7:72  
  36. //其余的桶为空  
  37. //按桶从小到大,同一个桶从左到右的顺序将全部元素放回数组x中  
  38. //x为[1,3,5,7,7,23,72],完毕  
  39.   
  40.     int dividend=1;  
  41.     for(int i=0;i<maxbit;i++)                       //从低位到高位分别处理  
  42.     {  
  43.         for(int j1=0;j1<x.length;j1++)          //将所有元素按照当前检测位的数字大小入桶  
  44.         {  
  45.             int index=(x[j1]/dividend)%radix;  
  46.             list.get(index).offer(x[j1]);  
  47.         }  
  48.         dividend*=10;  
  49.         int m=0;  
  50.         for(int j2=0;j2<radix;j2++)             //按桶从小到大,同一个桶从左到右的顺序将全部元素放回数组x中  
  51.         {  
  52.             while(list.get(j2).size()!=0)  
  53.             {  
  54.                 x[m]=(int) list.get(j2).poll();  
  55.                 m++;  
  56.             }  
  57.         }  
  58.     }  
  59. }  

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

空间复杂度:O(n)

稳定性:稳定

0 0
原创粉丝点击