排序算法

选择排序

定义:每次迭代过程中,我们都是从剩余元素(remaining entries)中选得最小的元素放在相应的位置上,这里的 不变量(invariant)为 左边已经排好序的部分。
特点:比较次数是 N(N-1)/2  交换次数是 N (each exchange puts an item into its final position, so the number of exchanges is N. Thus, the running time is dominated by the number of compares),数学模型是上三角;每一次寻找最小元素的过程不会为下一趟的寻找提供额外信息,所以对于一个有序的数组,仍然要花和一个随机数组一样长的时间;选择排序中数组访问是和数组尺寸线性相关的,这是其他排序不具有的。
实现
public  class  SelectionSort {

      // This class should not be instantiated.
      private  SelectionSort() {
     }

      // ascending order
      public  static  void  sort(Comparable[] a) {
            int  N = a. length  ;
            for  ( int  i = 0; i < N; i++) {
                int  min = i;
                for  ( int  j = i + 1; j < N; j++) {
                     if  (less(a[j], a[min]))
                        min = j;
              }
               exch(a, i, min);
                assert  isSorted(a, 0, i);
          }
            assert  isSorted(a);
     }

      /***********************************************************************
      * Helper sorting functions
      ***********************************************************************/

      // is v < w ?
      private  static  boolean  less(Comparable v, Comparable w) {
            return  (v.compareTo(w) < 0);
     }

      // exchange a[i] and a[j]
      private  static  void  exch(Object[] a,  int  i,  int  j) {
          Object swap = a[i];
          a[i] = a[j];
          a[j] = swap;
     }

      /***********************************************************************
      * Check if array is sorted  -  useful for debugging
      ***********************************************************************/
      // is the array a[] sorted?
      private  static  boolean  isSorted(Comparable [] a) {
            return  isSorted(a, 0, a.  length  - 1);
     }

      // is the array sorted from a[lo] to a[ hi]
      private  static  boolean  isSorted(Comparable [] a,  int  lo,  int  hi) {
            for  ( int  i = lo + 1; i <= hi; i++)
                if  (less(a[i], a[i - 1]))
                     return  false  ;
            return  true  ;
     }

      // print array to standard output
      private  static  void  show(Comparable[] a) {
            for  ( int  i = 0; i < a. length ; i++) {
              System.  out .print(a[i] +  " "  );
          }
     }

      public  static  void  main(String[] args) {
          Integer[] a = { 10, 45, 0, 8, 7, -34, 20 };
          SelectionSort. sort(a);
           show(a);
     }
}

插入排序

定义:可以联系到扑克牌,每次都是将一个数字插入到一个有序序列的合适位置,为了给其腾出空间,需要后移比他大的元素。
特点:虽然在当前元素(current index)左边都是有序的,但是却不是他们的最终位置;对于一个随机数组,假设每次在插入一个元素时都是移动一半,则#compare=N^2/4,#exchange= N^2/4 ;最坏情况是每次都是插入到第一个位置(和选择排序一样了)是N^2/2,最好情况是已经有序,只需要比较N-1次。
如果数组中倒置的数量小于数组大小的常数倍数,那么称这样的数组是部分有序的,插入排序对于这样的数组很有效。(倒置是一个序列中乱序的键值对的个数,比如AEDC中的倒置有E-D,E-C,D-C,也就是需要变换位置的pair)
实现
public  class  InsertionSort {
      //其他代码同上
      // ascending order
      public  static  void  sort(Comparable[] a) {
            int  N = a. length  ;
            for  ( int  i = 0; i < N; i++) {
                for  ( int  j = i; j > 0 && less (a[j], a[j - 1]); j--) {
                    exch(a, j, j - 1);
              }
          }
     }
}

希尔排序

定义:对于大规模乱序数组插入排序很慢,因为它只交换相邻的元素,所以元素只能一步步的从这一端移动到另一端;希尔排序在插入排序的基础上做了改进,先对几个交错的序列进行局部排序(比如步长是h的子数组)这样加快了元素交换的速度,没一次的h-sort都会使得数组越来越有序,然后逐渐改变增长序列,直到最终得到有序数组。希尔排序在数组的尺寸和部分有序直接做了权衡,部分有序的程度取决于增长序列。
特点 至今没有发现一个最优的增量序列,使用递增序列(3x+1) 1, 4, 13, 40, 121, 364…的希尔排序所需的比较次数不会超出 N 的若干倍 乘以递增序列的长度。
在这个增量序列下,shellsort最多比较次数是N^(3/2).
实现
public  class  ShellSort {

      // This class should not be instantiated.
      private  ShellSort() {
     }

      // ascending order
      public  static  void  sort(Comparable[] a) {
            int  N = a. length  ;
            int  h = 1;
            // 找到最大的步长
            while  (h < N / 3)
               h = 3 * h + 1;  // 1,4,13,40
            while  (h >= 1) {
                // 用不同的增量来对子数组插入排序
                for  ( int  i = h ; i < N; i += h) {
                     for  ( int  j = i; j > 0 && less (a[j], a[j - h]); j -= h ) {
                         exch(a, j, j - h );
                   }
              }
               h /= 3;
          }
     }
}

Shuffle Sort

这里是利用排序的场景,洗牌算法
1.为每一张牌随机产生不同的数,而后利用上述的排序算法;
2. In iteration i, pick integer r between 0 and i uniformly at random. then Swap a[i] and a[r].(这是Knuth发明的)显然是线性复杂度。
实现:
public   class  TestShuffle {

       private   static   void  exch(  int [] a,  int  i,  int  j) {
            int  swap = a[i];
          a[i] = a[j];
          a[j] = swap;
     }

       public   static   void  shuffle(  int [] a) {
            int  N = a. length  ;
            for  ( int  i = 0; i < N; i++) {
                int  r = StdRandom.uniform(i + 1);  // 在 1-i之间产生随机数
               exch(a, i, r);
          }
     }

       public   static   void  main(String[] args) {
            int  [] test = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
           shuffle(test);
            for  ( int  i = 0; i < test.  length ; i++)
              System.  out  .print(test[i] +  " "  );
     }
}

归并排序

定义:利用分治思想,将大问题划分为小问题,然后进行合并。
特点:最大的优点是NlgN的复杂度(可以通过公式推导,或画递归树得到)
实现
public  class  MergeSort {
      private  static  Comparable[]  aux ;  // 辅助数组

      // This class should not be instantiated.
      private  MergeSort() {
     }

      public  static  void  sort(Comparable[] a) {
            aux  =  new  Comparable[a. length ];
           sort(a, 0, a. length  - 1);
     }

      // 递归子例程
      private  static  void  sort(Comparable[] a,  int  lo,  int  hi) {
            if  (hi <= lo)
                return ;
            int  mid = lo + (hi - lo) / 2;
           sort(a, lo, mid);
           sort(a, mid + 1, hi);
           merge(a, lo, mid, hi);
     }
       // in-place merge , not to get an output array
      public  static  void  merge(Comparable[] a,  int  lo,  int  mid,  int  hi) {
            int  i = lo, j = mid + 1, k;
            for  (k = lo; k <= hi; k++)
                aux [k] = a[k];
            // merge back to the original array a[lo.....hi]
            for  (k = lo; k <= hi; k++) {
                if  (i > mid)  // left is over
                   a[k] =  aux [j++];
                else  if  (j > hi)  // right is over
                   a[k] =  aux [i++];
                else  if  (less(  aux [i], a[j]))
                   a[k] =  aux [i++];
                else
                   a[k] = a[j++];
          }
     }
}

快速排序











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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值