Java排序总结

初级:1)冒泡排序

swap方法已在第一个代码中写好,等同三元组,在java中主要是引用思想。

public class BubbleSort{
    public static void swap(int[]a,int x,int y){//三元组swap静态方法
        int temp;
        temp = a[x];
        a[x] = a[y];
        a[y] = temp;
    }
    public static void bubbleSort(int[] a){
        for(int i = 0; i<a.length - 1;i++){//外循环排序次数
            for(int j=0; j<a.length - i - 1;j++){//内循环进行交换
                if(a[j]>a[j+1]){
                    swap(a,j,j+1);
                }
            }
        }
    }
}

   2)选择排序

思想:比较所有的数据项,取出最小值,放左边。比较剩下的数据,取最小,放最左。。。。
内层循环中,每一个in的新位置,数据项a[in]和a[min]比较,如果a[in]更小,则min被赋值为in的值,这里只是下标,没交换。到一次内层循环结束,再交换数据项。这样,最小数据项就会一直被放在左边。
比较的次数和冒泡是一样的,但是交换的次数小。因为交换数据需要在内存中移动,时间上要多(java语言中,影响不大,只是改变引用位置而已)

public class ChooseSort{
    public static void chooseSort(int []a,int nElems){
        int i,j,min;
        for(int i=0; i<nElems-1; i++){
            i=min;
            for(int j=i+1; j<nElems; j++){
                if(a[j]<a[min]){
                    min = j;
                }
                swap(a,j,min)
            }
        }
    }
}

  3)  插入排序

思想:假设左边已经排序好了,从某位置(比如10)开始无序,将10赋予给一临时值,然后和前面的数据比较,如果9位置比10大,就9右移一位,继续和8比较。。。直到到数据的最右边或找到比10位置的数据排好了。在大多数情况下,插入算法仍然需要0(N^2)的时间,但比冒泡快一倍,比选择排序也还要快一点。经常被用在比较复杂的排序算法的最后阶段,例如快排。


public class InsertSort{
    public static void insertSort(int []a,int nElem){
        int in,out;
        for(out = 0; out<nElem; out++){
        long temp = a[out];
        in = out; 
          while(in>0 && a[in-1] >=temp){
           a[in] = a[in-1];
           --in;
        }
        a[in] = temp;
     }
   }
 }​

外层的for循环中,out变量从1开始,向右移动,它标记了未排序部分的最左端的数据。
而在内层while循环中,in变量从out变量开始,向左移动,知道temp变量小于in所指的数组数据项,或者它已经不能再往左移动为止。while循环的每一次都向右移动了一个排序的数据项。

在每次结束时,在将temp位置的项插入后,比outer变量下标号小的数据项都是局部有序的。
比较次数,1+2+3+...+(N-1) = Nx(N-1)/2,而因为每一次排序发现插入点之前,平均只有全体数据项的一半真的进行了比较,所以是N*(N-1)/2 /2
复制的次数大致等于比较的次数。复制和交换的时间耗费不同。相对于随机数据,这个算法比冒泡快一倍,比选择排序略快。
对于已经有序或基本有序的数据来说,插入排序要好得多。对于逆序排列的数据,每次比较和移动都会执行,所以插入排序不比冒泡排序快。

中级:1)归并排序(时间复杂度为 O(NlogN))

归并排序的思想是:将一个数组分成两半,然后分别排序,然后将数组的两半合并,合并的时候需要比较大小(合并的时候还要考虑两小数组还有没有数据,即有可能一边有,另一边没有)。至于如何排序1/2半的数组,当然是再分成两个1/4数组,再排序。。。直到分割的小数组只有1个数据项,不用排序了。这是用到递归的思想
归并排序的缺点,需要在存储器中有另一个大小等于被排序的数据项数目的空间,用来复制分割出来的小数组。
归并算法的效率由来:需要复制log<sub>2</sub><sup>N</sup>层(分子数组),每一个层都是N个数据,所以是NxlogN.


int[] workSpace = new int[source.length];
recMergerSort(source,workSpace,0,length-1);
private static void reMergeSort(int[] source, int[] workSpace, int lowerBound, int upperBound){
    if(lowerBound == upperBound){
        return;
    }else{
        int mid = (lowerBound + upperBound) / 2;
        recMergeSort(source, workSpacce, lowerBound, mid);
        recMergeSort(source,workSpace,mid+1,upperBound);
    }
}

高级:Shell排序

希尔排序基于插入排序,但增加了一个新的特性,大大地提高了插入排序的执行效率。(希尔是个人名。。。)
改进的地方:插入算法中,如果一个数据比较小而居于最右边,那么它需要一个一个地移动所有中间的数据项,效率比较低。
希尔排序通过加入插入排序中元素之间的间隔,并在这些有间隔的元素中进行插入排序,从而使数据项能大跨度地移动。当这些数据项排过一趟序后,减小数据项的间隔。再进行排序,依次进行下去。间隔被称为增量,用h表示.
进行过几次增量排序后,所有的元素离它再最终有序序列中的位置相差不大,数组达到"基本有序",这时再来插入排序,移动量非常小。
当h值很大的时候,数据项每一趟排序需要移动元素的个数很少,但数据项移动的距离很长,这是非常有效率的。当h减少时,每一趟排序需要移动的元素的个数增多,但是此时数据项已经接近于它们排序后最终的位置,这对于插入排序可以更有效率。
其中,h = h x 3 +1, h = (h -1) / 3,是经验值。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值