《算法》2.2-归并排序

1. 基本思想

①Divide array into two halves.
②Recursively sort each half.
③Merge two halves.
将数组分成两部分,两部分分别排好序,最后将两个有序的子数组整合成一个有序的数组。


归并排序

注意:input数组是归并排序需要的额外空间。results数组是输入数组排序后的结果。

    // stably merge a[lo .. mid] with a[mid+1 ..hi] using aux[lo .. hi]
    private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
        // precondition: a[lo .. mid] and a[mid+1 .. hi] are sorted subarrays
        assert isSorted(a, lo, mid);
        assert isSorted(a, mid+1, hi);
        // copy to aux[]
        for (int k = lo; k <= hi; k++) {
            aux[k] = a[k]; 
        }
        // merge back to a[]
        int i = lo, j = mid+1;
        for (int k = lo; k <= hi; k++) {
            if      (i > mid)              a[k] = aux[j++];
            else if (j > hi)               a[k] = aux[i++];
            else if (less(aux[j], aux[i])) a[k] = aux[j++];
            else                           a[k] = aux[i++];
        }
        // postcondition: a[lo .. hi] is sorted
        assert isSorted(a, lo, hi);
    }

2. 自顶向下的归并排序

  1. Code
 // mergesort a[lo..hi] using auxiliary array aux[lo..hi]
    private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
        if (hi <= lo) return;
        int mid = lo + (hi - lo) / 2;
        sort(a, aux, lo, mid);
        sort(a, aux, mid + 1, hi);
        merge(a, aux, lo, mid, hi);
    }
//调用方法   
    public static void sort(Comparable[] a) {
        Comparable[] aux = new Comparable[a.length];
        sort(a, aux, 0, a.length-1);
        assert isSorted(a);
    }
  1. Example
    top-down归并排序

    要理解递归调用的次序:

    3.分析
    ①长度为N的数组使用归并排序最多需要NlgN次比较。每次归并最多N次比较,最少N/2次比较。
    C (N) ≤ C (⎡N / 2⎤) + C (⎣N / 2⎦) + N for N > 1, with C (1) = 0

    ②长度为N的数组自顶向下归并排序最多需要访问数组6NlgN次。
    每次归并需要aux[k] = a[k]最多访问2N次数组,每次归并最多进行N次比较,每次比较访问2个元素,比较共2N次访问数组,最后将排好序的结果拷贝到原始数组中a[k] = aux[XX]需要2N次访问数组。
    ③归并排序需要N个额外的存储空间。

3. 自底向上的归并排序

  1. Code
 public static void sort(Comparable[] a) {
        int n = a.length;
        Comparable[] aux = new Comparable[n];
        //len代表子数组的大小
        for (int len = 1; len < n; len *= 2) {
            for (int lo = 0; lo < n-len; lo += len+len) {
                int mid  = lo+len-1;
                int hi = Math.min(lo+len+len-1, n-1);
                merge(a, aux, lo, mid, hi);
            }
        }
        assert isSorted(a);
    }
  1. Example
    bottom up归并排序

4. 排序算法的复杂度

没有任何基于比较的算法能够保证使用少于lg(N!)~NlgN次比较将长度为N的数组排序。
排序树:假设有N=3,a[0],a[1],a[2]三个元素。


排序树

①一定有N!个叶子结点,每个结点代表了一种排序的结果。
②从根节点到叶子结点的一条路上的内部结点的数量是某种输入情况下算法的比较次数。
③从根节点到叶子结点路径有多长?最坏的输入下高度为h的二叉树最多有2^h个叶子结点。


完全二叉树

最坏情况下的比较次数就是h,任意算法的比较次数至少是lgN!~NlgN
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 最近在读< >时,了解到了很多常用的排序算法,故写一篇读书笔记记录下这些排序算法的思路和实现. 冒泡排序 冒泡排序...
    SylvanasSun阅读 733评论 0 0
  • 一. 写在前面 要学习算法,“排序”是一个回避不了的重要话题,在分析完并查集算法和常用数据结构之后,今天我们终于可...
    Leesper阅读 2,571评论 0 40
  • 数据结构与算法--归并排序 归并排序 归并排序基于一种称为“归并”的简单操作。比如考试可能会分年级排名和班级排名,...
    sunhaiyu阅读 930评论 0 6
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,293评论 0 2
  • 我们这帮闺蜜,论驾龄全部能称得上老司机的名号,任何一个人的驾照拿出来都是好几年,最长的达15年。可是,就没有一个人...
    轻描S阅读 431评论 0 1