歸併排序

歸併排序

歸併排序(MERGE-SORT)是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將一個待排序數組a從中間分爲吧b,c兩個數組,然後遞歸的將b和c繼續劃分,直到子數組的長度爲1,然後開始向上依次進行合併,即將兩個有序數組合併爲一個數組(長度爲1的數組必定是有序的)。

舉個例子,現在有一個數組爲{6,20,10,31,38,8,1,25}
第一趟劃分:{6,20,10,31},{38,8,1,25}
第二趟劃分:{ {6,20},{10,31} },{ {38,8},{1,25} }
第三趟劃分:{ { {6} ,{20}},{{10},{31}} },{ {{38},{8}},{{1},{25}} }
這個時候每一段都已經無法再分了,便開始依次合併。將長度爲N的數組劃分到最小需要logN次,所以劃分的時間複雜度爲O(logN)
第一趟合併:{{6,20},{10,31},{8,38},{1,25}}
第二趟合併:{{6,10,20,31},{1,8,25,38}}
第三趟合併:{1,6,8,10,20,25,31,38}
這個時候數組合並完畢,已經完全有序。合併的過程就是將兩個數組放到另外一個長度爲N的數組中,所以時間複雜度爲O(N),空間複雜度爲數組的大小N。合併的時候是基於比較的,所以相等元素的順序不會改變,即穩定的排序。

  // 歸併排序
    static public void mergeSort(int a[]) {
        int[] b = new int[a.length];//合併時複製的數組
        mergeSort(a, b, 0, a.length - 1);
    }

    public static void mergeSort(int a[], int b[], int left, int right) {
        // 只有一個數時,直接跳出
        if (left == right) {
            return;
        }
        int mid = (left + right) / 2;
        // 還未到最小劃分時,繼續劃分
        if (right - left > 1) {
            mergeSort(a, b, left, mid);
            mergeSort(a, b, mid + 1, right);
        }
        int center = mid;
        mid++;
        int cursor = left;
        int start = left;
        // 合併兩個已排序的數組到b中
        while (left <= center && mid <= right) {
            if (a[left] <= a[mid]) {
                b[cursor++] = a[left++];
            } else {
                b[cursor++] = a[mid++];
            }

        }
        while (left <= center) {
            b[cursor++] = a[left++];
        }
        while (mid <= right) {
            b[cursor++] = a[mid++];
        }
        // 將b中已排序的數移回a中
        for (int i = start; i <= right; i++) {
            a[i] = b[i];
        }
    }

可以看出,歸併排序實際上分爲兩步,劃分合併任何情況下,劃分的時間複雜度都爲O(logN),合併的時間複雜度都爲O(N),總共就是O(N*logN)。可以看出,歸併的效率還是比較高的,但是會耗費額外的空間。相比較快排,歸併是穩定的,這也是優勢所在。

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