1. 程式人生 > >八大排序(二):歸併排序

八大排序(二):歸併排序

歸併排序(MERGE-SORT)是建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。分治法即將問題分(divide)成一些小的問題然後遞迴求解,而治(conquer)的階段則將分的階段得到的各答案”修補”在一起,歸併排序的速度僅次於快速排序,比較次數小於快速排序的比較次數,而移動次數一般多於快速排序的移動次數。

歸併排序的過程可以結合下圖來理解:
這裡寫圖片描述

其中,“治”階段的過程如下圖:
這裡寫圖片描述

一般歸併排序的程式碼把“分”和“治”的操作分開了,以下的的程式碼把劃分和合併合在一起,用空格隔開了。歸併排序和之前劍指offer-題36:陣列中的逆序對

的思路相似。注意在mergeSortCore函式中再次遞迴呼叫mergeSortCore函式的傳值:將array和tempArray的順序調換了一下,原因可以這樣理解:
在最後一層遞迴呼叫後,tempArray會是排序完成的結果,而array是排序之前的結果。此時把結果返回給倒數第二層,注意,此時倒數第二層array對應最後一層的tempArray,而tempArray對應array,也就是說倒數第二層的array是上一層最新的排序好的結果,而tempArray是次新的結果。在倒數第二層經過後半段的排序後,此時的tempArray會成為最新排序好的結果返回倒數第三層的array,而array會作為次新的結果返回給倒數第三層的tempArray(可能把你繞暈了,可以畫一個圖方便理解)。根據這個規律,執行到遞迴最開始的那一層時,array是最新排序好的,在程式的後半段,再根據array的順序進行最後一次歸併,tempArray會成為最終排序的結果,因此最後返回的結果是tempArray。具體程式碼如下

歸併排序:

    public float[] mergeSort(float[] array) {
        float[] tempArray = new float[array.length];
        System.arraycopy(array, 0, tempArray , 0, array.length);
        mergeSortCore(array, tempArray, 0, array.length - 1);
        return tempArray;
    }

    // 歸併排序
    public void mergeSortCore(float
[] array, float[] tempArray, int start, int end) { if (start == end) { tempArray[start] = array[start]; return; } else if (start < end) { int middle = (start + end) >> 1; mergeSortCore(tempArray, array, start, middle); mergeSortCore(tempArray, array, middle + 1, end); int i = start; int j = middle + 1; int k = start; while (i <= middle && j <= end) { if (array[i] <= array[j]) { tempArray[k++] = array[i++]; } else { tempArray[k++] = array[j++]; } } while (i <= middle) { tempArray[k++] = array[i++]; } while (j <= end) { tempArray[k++] = array[j++]; } } }