18种排序

转自:http://blog.csdn.net/liyue199512/article/details/52137021?locationNum=1&fps=1 
一、冒泡排序
依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的)。第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。

[java]  view plain  copy
  1. public static void sort(int[] a){//冒泡排序  
  2.     int temp;    
  3.     boolean swap;  
  4.     for(int i=0;i<a.length-1;i++){    
  5.         swap=false;  
  6.         for(int j=0;j<a.length-1-i;j++){    
  7.             if(a[j]>a[j+1]){    
  8.                 temp=a[j];    
  9.                 a[j]=a[j+1];    
  10.                 a[j+1]=temp;  
  11.                 swap=true;  
  12.             }  
  13.         }  
  14.         if(!swap){  
  15.             break;  
  16.         }  
  17.     }    
  18. }    

二、直接选择排序
每一趟从待排序的数据元素中选出最小的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。

[java]  view plain  copy
  1. public static void sort(int[] a){//直接选择排序  
  2.     for (int i=0;i<a.length-1;i++) {   
  3.         int min = i;  
  4.         for (int j=i+1;j<a.length;j++){//找还未排序的最小值  
  5.             if (a[min]>a[j]){  
  6.                     min=j;  
  7.                     }  
  8.             }  
  9.             int temp;  
  10.             if (min!=i) {  
  11.                 temp=a[i];  
  12.                 a[i]=a[min];  
  13.                 a[min]=temp;  
  14.             }  
  15.         }  
  16. }   

三、直接插入排序
每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子文件中的适当位置,直到全部记录插入完成为止。

[java]  view plain  copy
  1. public static void sort(int[] a){//直接插入排序    
  2.     for(int i=1;i<a.length;i++){    
  3.         int temp=a[i];  
  4.         int j;  
  5.         for(j=i-1;j>=0&&temp<a[j];j--){//将大于temp的值整体后移一个单位     
  6.             a[j+1]=a[j];                          
  7.         }   
  8.         a[j+1]=temp;    
  9.     }    
  10. }    

四、快速排序

快速排序是对冒泡排序的一种改进。选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

[java]  view plain  copy
  1. public static void sort(int[] a){//快速排序    
  2.     quicksort(a,0,a.length-1);  
  3. }  
  4. public static void quicksort(int[] a,int left,int right){  
  5.     int i,j,t,temp;  
  6.     if(left>right){  
  7.         return;  
  8.     }  
  9.     temp = a[left];  
  10.     i=left;  
  11.     j=right;  
  12.     while(i!=j){  
  13.         while(a[j]>=temp && i<j){  
  14.             j--;  
  15.         }  
  16.         while(a[i]<=temp && i<j){  
  17.             i++;  
  18.         }  
  19.         if(i<j){  
  20.             t=a[i];  
  21.             a[i]=a[j];  
  22.             a[j]=t;  
  23.         }  
  24.     }  
  25.     a[left]=a[i];  
  26.     a[i]=temp;  
  27.     quicksort(a,left,i-1);  
  28.     quicksort(a,i+1,right);  
  29. }  
五、堆排序

使用数据结构堆。
堆是完全二叉树或者是近似完全二叉树。
堆满足二个特性:
1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。
由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN)。二次操作时间相加还是O(N * logN)。故堆排序的时间复杂度为O(N * logN)。

[java]  view plain  copy
  1. class Heap{  
  2.     private int currentSize;  
  3.     private int [] array;  
  4.     public Heap(int[] array){  
  5.         this.array = array;  
  6.         this.currentSize = array.length;  
  7.     }  
  8.     public int findMin(){  
  9.         if(currentSize==0){  
  10.             System.out.println("当前堆里已经没有值了!!!!没有最小的了!!!");  
  11.             return -1;//  
  12.         }  
  13.         int min = array[0];//最小堆的根节点是最小的  
  14.         //删除最小元,由于现在堆少了一个元素,因此堆中最后一个元素X必须移动到该堆的某个地方。  
  15.         //把根节点当做空穴,如果X能放到空穴中,deleteMin完成。但一般不会出现这种情况。  
  16.         array[0] = array[currentSize-1];//先将最后一个元素放到空穴  
  17.         currentSize--;//当前堆的Size减1  
  18.         //尝试将空穴中的两个儿子较小的放入空穴,把空穴下移一层。重复该步骤直到X可以被放入空穴  
  19.         //注意:堆有偶数个元素的时候,有个节点将会只有一个孩子。  
  20.         down(0);//将X置入沿着从根开始包含最小儿子的一条路径上的正确位置  
  21.         return min;  
  22.           
  23.     }  
  24.     public void down(int hole){//下滤,将空穴中的值X放到合适的位置  
  25.         int child;//孩子节点  
  26.         int temp = array[hole];//temp=X的值  
  27.         for(;hole*2<=currentSize;hole=child){//如果有左孩子  
  28.             child = hole*2;//child=空穴的左孩子  
  29.             if(child!=currentSize&&array[child+1]<array[child]){//如果还有右孩子,且右孩子更小  
  30.                 child++;//child=空穴的右孩子  
  31.             }  
  32.             if(array[child]<temp){//如果孩子节点的值比空穴的值小  
  33.                 array[hole]=array[child];//将孩子移入空穴  
  34.             }  
  35.             else  
  36.                 break;  
  37.             //新的空穴是原来的空穴的最小孩子  
  38.         }  
  39.         array[hole] = temp;//将X移入空穴  
  40.     }  
  41.     public void buildHeap(){  
  42.         for(int i=currentSize/2-1;i>=0;i--){//从后往前遍历非叶节点,通过下滤,将把该节点作为根的子树变成堆  
  43.             down(i);  
  44.         }  
  45.     }  
  46. }  
[java]  view plain  copy
  1. public static void sort(int[] a){//堆排序    
  2.     Heap heap = new Heap(a);  
  3.     heap.buildHeap();  
  4.     for(int i=a.length-1;i>=0;i--){  
  5.         a[i]=heap.findMin();  
  6.     }  
  7. }  

六、希尔排序(Shell排序)
希尔排序的实质就是分组插入排序,该方法又称缩小增量排序。先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。

[java]  view plain  copy
  1. public static void sort(int[] a){//Shell排序  
  2.     int j;          
  3.         for (int gap=a.length/2; gap>0; gap/=2)//步长每次折半,逐步缩短至一    
  4.             for (int i=0;i<gap;i++){//每个分组进行直接插入排序    
  5.                 for (j=i+gap;j<a.length;j+=gap){//从每个分组的第二个值开始遍历该分组的每个值,每个值的距离是gap   
  6.                         if (a[j]<a[j-gap]){//如果后一个值小于前一个值    
  7.                                 int temp=a[j];//temp等于后一个值  
  8.                                 int k;  
  9.                                 for(k=j-gap;k>=0&&a[k]>temp;k-=gap){  
  10.                                     a[k+gap]=a[k];//后移   
  11.                                 }  
  12.                             a[k+gap] = temp;    
  13.                     }  
  14.             }  
  15.         }   
  16. }  

七、归并排序
用分治法思想解决排序问题。
将数组分成二组,如果这二组组内的数据都是各自有序的,那么就可以很方便的将这二组数据合并成有序。可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。
设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。

[java]  view plain  copy
  1. public static void mergeArray(int a[],int first,int mid,int last,int temp[]){    
  2.     int i=first,j=mid+1,m=mid,n=last;    
  3.     int k=0;    
  4.     while(i<=m&&j<=n){//当i,j都不越界时    
  5.         if(a[i]<=a[j])//如果左边的小    
  6.             temp[k++]=a[i++];//把左边的放入temp数组    
  7.         else    
  8.             temp[k++]=a[j++];//如果右边的小,把右边的放入temp数组    
  9.     }     
  10.     while(i<=m)//如果左边有剩余,继续放入temp    
  11.         temp[k++]=a[i++];    
  12.     while(j<=n)//如果右边有剩余,继续放入temp    
  13.         temp[k++]=a[j++];    
  14.     for(i=0;i<k;i++)//合并结果放回    
  15.         a[first+i]=temp[i];    
  16. }    
  17. public static void mergeSort(int a[],int first,int last,int temp[]){    
  18.     if(first<last){    
  19.         int mid=(first+last)/2;    
  20.         mergeSort(a,first,mid,temp);//左边排序   
  21.         mergeSort(a,mid+1,last,temp);//右边排序    
  22.         mergeArray(a,first,mid,last,temp);//合并有序数列  
  23.     }    
  24. }     
  25. public static void sort(int a[]){//归并排序  
  26. int[] temp=new int[a.length];  
  27.     mergeSort(a,0,a.length-1,temp);  
  28. }  

八、基数排序

先按个位数排序,再按十位数排序,再按百位数排序……

[java]  view plain  copy
  1. public static int getDigit(int x, int d){//获取x这个数的d位数上的数字,比如获取123的1位数,结果返回3  
  2.     int a[]={0,1,10,100,1000,10000,100000}; //假设最大不超过6位  
  3.     return ((x/a[d])%10);  
  4. }  
  5. public static void radixSort(int[] a,int digit){  
  6.     final int radix=10;//基数  
  7.     int i=0,j=0;  
  8.     int[] count=new int[radix];//存放各个桶的数据统计个数  
  9.     int[] bucket=new int[a.length];  
  10.     //按照从低位到高位的顺序执行排序过程  
  11.     for(int d=1;d<=digit;d++){  
  12.         //置空各个桶的数据统计  
  13.         for(i=0;i<radix;i++) {  
  14.             count[i]=0;  
  15.         }  
  16.         //统计各个桶将要装入的数据个数  
  17.         for(i=0;i<a.length;i++) {  
  18.             j=getDigit(a[i],d);  
  19.             count[j]++;  
  20.         }  
  21.         //count[i]表示第i个桶的右边界索引  
  22.         for(i=1;i<radix;i++) {  
  23.             count[i]=count[i]+count[i-1];  
  24.         }  
  25.         //将数据依次装入桶中  
  26.         //这里要从右向左扫描,保证排序稳定性  
  27.         for(i=a.length-1;i>=0;i--) {  
  28.             j=getDigit(a[i],d);  
  29.             bucket[count[j]-1]=a[i];//放入对应的桶中,count[j]-1是第j个桶的右边界索引  
  30.             count[j]--;//对应桶的装入数据索引减一  
  31.         }  
  32.         //将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表  
  33.         for(i=0,j=0;i<a.length;i++,j++){  
  34.             a[i]=bucket[j];  
  35.         }  
  36.     }  
  37. }  
  38. public static int[] sort(int[] a) {//基数排序  
  39.     radixSort(a, 2);  
  40. }  

九、二叉树排序

排序二叉树的性质如下:
若他的左子树不空,则左子树上所有的结点均小于它的根结点的值。
若他的右子树不空,则右子树上所有的结点均大于它的根结点的值。
他的左右子树也是排序二叉树。
构建排序二叉树,中根遍历就是从小到大排序。

[java]  view plain  copy
  1. class Tree{  
  2.     private static class TreeNode{  
  3.         int element;  
  4.         TreeNode left;  
  5.         TreeNode right;  
  6.         TreeNode(int element){  
  7.             this(element,null,null);  
  8.         }  
  9.         TreeNode(int element,TreeNode left,TreeNode right){  
  10.             this.element=element;  
  11.             this.left=left;  
  12.             this.right=right;  
  13.         }  
  14.     }  
  15.     private TreeNode root;  
  16.     public void insert(int x){  
  17.         root=insert(x,root);  
  18.     }  
  19.     public TreeNode insert(int x,TreeNode t){  
  20.         if(t==null){  
  21.             return new TreeNode(x,null,null);  
  22.         }  
  23.         if(x<t.element){  
  24.             t.left=insert(x,t.left);  
  25.         }else if(x>=t.element){  
  26.             t.right=insert(x,t.right);  
  27.         }  
  28.         return t;  
  29.     }  
  30.     public void printAll(){  
  31.         print(root);  
  32.     }  
  33.     public void print(TreeNode t){  
  34.         if(t!=null){  
  35.             print(t.left);  
  36.             System.out.print(t.element+" ");  
  37.             print(t.right);  
  38.         }  
  39.     }  
  40. }  
[java]  view plain  copy
  1. public static void sort(int a[]){//二叉树排序  
  2.     Tree tree = new Tree();  
  3.     for(int i=0;i<a.length;i++){  
  4.         tree.insert(a[i]);  
  5.     }  
  6.     tree.printAll();  
  7. }  

十、计数排序
找出数在数组中不大于它的数有多少个,从而确定位置。 比较排序算法可以通过决策树模型证明,其下限是O(nlgn),计数排序算法不是一个基于比较的排序算法,所以不受比较排序下限影响。

[java]  view plain  copy
  1. public static int[] sort(int[]a){//计数排序  
  2.     int b[]=new int[a.length];  
  3.     int max=a[0],min=a[0];  
  4.     for(int i:a){//找到最大最小值  
  5.         if(i>max){  
  6.             max=i;  
  7.         }  
  8.         if(i<min){  
  9.             min=i;  
  10.         }  
  11.     }  
  12.     int k=max-min+1;//数组长度是极值差+1,因为最小值-最小值=0,范围是0~最大值-最小值  
  13.     int c[]=new int[k];  
  14.  for(int i=0;i<a.length;i++){  
  15.         c[a[i]-min]+=1;//值-最小值  
  16.     }  
  17.     for(int i=1;i<c.length;i++){//计数,c角标代表:值-最小值,c中数代表有多少个不大于这个值的数。  
  18.         c[i]=c[i]+c[i-1];  
  19.     }  
  20.     for(int i=a.length-1;i>=0;--i){//找到a[i]应该在什么位置,根据有多少个数不大于a[i]。  
  21.         b[--c[a[i]-min]]=a[i];//b从0开始放,所以是计数-1;数被放置好了,计数应该-1  
  22.     }  
  23.     return b;  
  24. }  

十一、鸽巢排序
最初时辅助数组中初始化为0,扫描待排序数组时,将待排序序列中的每一个数减去最小值当作辅助数组中的下标自增1。则,扫描完成时,也就间接的完成了排序。之后只需要扫描一遍辅助数组,若辅助数组中有非零的数据,则该位置的下标加上最小值就是待排序数组中原来的数据。借之完成了排序。

[java]  view plain  copy
  1. public static void sort(int[]a){//鸽巢排序    
  2.     //int b[]=new int[a.length];    
  3.     int max=a[0],min=a[0];    
  4.     for(int i:a){//找到最大最小值    
  5.         if(i>max){    
  6.             max=i;    
  7.         }    
  8.         if(i<min){    
  9.             min=i;    
  10.         }    
  11.     }    
  12.     int k=max-min+1;//数组长度是极值差+1,因为最小值-最小值=0,范围是0~最大值-最小值    
  13.     int c[]=new int[k];    
  14.  for(int i=0;i<a.length;i++){    
  15.         c[a[i]-min]+=1;//值-最小值    
  16.     }    
  17.     int j=0;    
  18.     for(int i=0;i<c.length;i++){//c中的数表示有几个“角标+最小值”那么大的数    
  19.         while(c[i]>0){    
  20.             a[j]=i+min;//一个个数从小到大放到a中    
  21.             j++;    
  22.             c[i]--;    
  23.         }    
  24.     }    
  25. }    

对计数排序和鸽巢排序的思考:http://blog.csdn.net/liyue199512/article/details/52149489


十二、桶排序
例如要对大小为[1..1000]范围内的n个整数A[1..n]排序,可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1..10]的整数,集合B[2]存储(10..20]的整数,……集合B[i]存储((i-1)*10, i*10]的整数,i = 1,2,..100。总共有100个桶。然后对A[1..n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。 然后再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任何排序法都可以。最后依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这样就得到所有数字排好序的一个序列了。

十三、鸡尾酒排序(鸡尾酒搅拌排序/搅拌排序/ 涟漪排序/来回排序 /快乐小时排序)
是冒泡排序的改进, 从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能,原因是冒泡排序只从一个方向进行比对(由低到高),每次循环只移动一个项目。

十四、奇偶排序
第一趟扫描选择所有的数据项对,a[j]和a[j+1],j是奇数。    如果它们的关键字的值次序颠倒,就交换它们。   第二趟扫描对所有的偶数数据项进行同样的操作(j=2, 4,6……)。   重复进行这样两趟的排序直到数组全部有序。   

十五、折半插入排序
是插入排序的改进, 由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。


十六、珠排序
http://blog.csdn.net/liyue199512/article/details/52261062

十七、地精排序
http://blog.csdn.net/liyue199512/article/details/52261080

十八、Strand Sort
http://blog.csdn.net/liyue199512/article/details/52261090


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值