Princeton Algorithms, Part I week2 Merge Sort

发布时间 2023-11-14 22:52:39作者: gauss_j

Merge sort

今天学习merge sort

这个排序算法的思想就是,不停的将数组二分,再将两个子数组不停归并。其中有一个操作叫merge如下图所示。左右两边两个部分是有序的,然后思想也很简单 有两个指针i和j,i指向lo,j指向mid+1,然后比较两个指针所指的大小,如果小就选出来排到数组中,如果i大于mid了 直接将j指针所指内容一直放入数组,反之亦然。

 下面是merge操作的java implementation

 1 public class MergeSort{
 2 
 3         private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi){           // 把item复制到aux数组里面
 4                      for(int i = lo;i <= hi,i++) aux[i] = a[i];
 5                      
 6                      int i = lo, j = mid+1;
 7                      for(int k = lo;k <= hi;k++){
 8 
 9                         if(i > mid) a[k] = aux[j++];
10                         else if (j > hi) a[k] = aux[i++];
11                         else if (less(a[i], a[j]))  a[k] = a[i++];
12                         else  a[k] = a[j++];
13 
14 }
15 
16 
17 }
18 
19 }

这段代码应该很好理解

下面是merge sort的完整java implementation

 1 public class MergeSort{
 2            private static void merge(...){// as before}
 3            private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi){
 4 
 5                        if(hi <= lo) return;
 6                        int mid = lo + (hi - lo)/2;
 7                        sort(a, aux, lo, mid);
 8                        sort(a, aux, mid+1, hi);
 9                        merge(a,aux,lo, mid, hi);
10 }
11           public static void sort(Comparable[] a){
12                      Comparable[] aux = new Comparable[a.length];
13                      sort(a, aux, 0, a.length - 1);
14 
15 
16 }
17 
18 }

值得一提的是 merge sort 对于大小为N的数组,排序用的比较次数最多为N lg N,访问次数最多为 6 N lg N。

下面是一个简短的证明

 这里我们假设N是2的幂次方

 两边同时乘以N就可以得到前面的命题了。比较次数和访问次数的证明类似。

Merge Sort在时间复杂度上是最优的算法,但是缺点是他需要用额外的空间来保存数组的元素也就是aux数组。

此外再引入 sort stability的概念

就是当我们已经用一个排序算法比如selection sort对item 的某个key排序以后,然后再用另外一个算法,比如 insertion sort,如果说第二次里面相同的key的item 再第二次排序以后他们第一次的key相对位置任然有序,就说第二种算法是稳定的。

不稳定的算法:shell sort,selection sort

稳定的:insertion sort, merge sort