week3——歸併排序

聲明

本文是博主在Coursera學習時所寫的學習筆記,如有錯誤疏漏還望各位指正。

歡迎交流討論

如果大家轉載,請註明本文地址!

歸併排序

基本思想

  • 將列表分爲兩部分
  • 通過遞歸將每部分排序
  • 合併兩部分
    這裏寫圖片描述

舉個例子

輸入一個數組 G,E,E,M,R,C,E,A,R,T
將其分爲兩部分,並對每個部分排序,如下圖
這裏寫圖片描述

合併兩部分
這裏寫圖片描述
新建一個aux[]的拷貝a[]
設兩部分最小元素的下標爲i,j,每次比較i,j所對應的元素大小,將較小的元素放入a[],讓後將i或j加1,直至將兩部分合並完成。

算法分析

  • 時間複雜度
    比較次數:O(NlogN)
    數組訪問次數:O(6NlogN)
  • 空間複雜度
    需要額外的O(N) ,這是歸併排序最明顯的缺點

代碼實現

    public class MergeSort {

    //合併
    private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
        for (int k = lo; k <= hi; k++)
            aux[k] = a[k];
        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++];
        }
    }

    private static boolean less(Comparable a, Comparable b) {
        return a.compareTo(b) < 0;
    }

    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);
    }
}

改進

對劃分後較小的數組使用插入排序

因爲遞歸的原因,歸併排序對較小的數組有很大開銷,因此對較小的數組我們改用插入排序
將上述的sort(Comparable[] a, Comparable[] aux, int lo, int hi)改爲如下:

private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi)
{
    //當數組長度小於CUTOFF時使用插入排序,CUTOFF應設置爲常數。
    if (hi <= lo + CUTOFF - 1)
    {
        Insertion.sort(a, lo, hi);
        return;
    }
    int mid = lo + (hi - lo) / 2;
    sort (a, aux, lo, mid);
    sort (a, aux, mid+1, hi);
    merge(a, aux, lo, mid, hi);
}

如果歸併前排序已經完成則停止

對劃分後的兩部分分別排序後,如果左邊最大的元素小於右邊最大的元素,則不要進行歸併
將sort(Comparable[] a, Comparable[] aux, int lo, int 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);

    //新添加的代碼
    if (!less(a[mid+1], a[mid])) return;

    merge(a, aux, lo, mid, hi);
}

自下而上歸併排序

基本思想

將數組劃分爲長度爲1的若干數組,合併成爲長度爲2的若干數組。
將長度爲2的書組合併成長度爲4的若干數組。以此類推,直至排序完成。

舉個例子

這裏寫圖片描述

示例圖

這裏寫圖片描述

代碼實現

將sort(Comparable[] a)改爲如下:


public static void sort(Comparable[] a)
{
    int N = a.length;
    Comparable[] aux = new Comparable[N];
    for (int sz = 1; sz < N; sz = sz+sz)//每次歸併的數組長度,1,2,4,8....
        for (int lo = 0; lo < N-sz; lo += sz+sz)//每次歸併的子數組a[lo]~a[N-sz]
            merge(a, aux, lo, lo+sz-1, Math.min(lo+sz+sz-1, N-1));
}

說明

這種自下而上的歸併排序是一種簡單的無遞歸歸併排序,但是要大約比應用遞歸的自頂而下的歸併排序慢10%

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章