1. 程式人生 > >知識點11:常見的排序演算法–歸併排序

知識點11:常見的排序演算法–歸併排序

相信看過常見的排序演算法——快速排序的朋友們都記得,我們在介紹它的時候便闡述了使用快排的兩種策略,分別是分治和遞迴。它的原理是:通過遞迴的方式,利用某個基底,不斷將數列劃分為更小的部分。直到小陣列不能再拆分的時候,便已經完成了排序。而今天要介紹的歸併排序,與它有很多相近的地方,不過也有很多的不同,讓我們一起來探討一下吧:

歸併排序的原理

通過遞迴和分治的策略,以兩個有序陣列的歸併為底板。將數列劃分為若干有序個小數列,然後通過底板將其歸併為一個已經排序的新數列。那麼,我們如何確定兩個數列是有序數列呢?那麼試想,當小數列內部的元素為2時,它是否就已經可以進行排序,使其成為一個有序陣列了呢?。不過,在這個問題上,有兩種分歧。分別是:從一個數列開始,每次對半劃分,直到出現有序序列後遞迴排序(自頂而上排序)和一次性將數列劃分為元素為2的若干個有序序列,然後再進行遞迴。這兩種方式實際上都是同樣的,只是在分治理念上有點偏差。我們先來看一下我們的核心程式碼,也就是底板的實現:

/*
*兩個有序陣列的排序方法
*arr 資料來源
*start 左邊陣列起始
*mid   左邊陣列結束
*end   右邊陣列結束
*/
public static void merge(int[] arr,int start,int mid,int end){
        int i = start;
        int j = mid+1;//右邊陣列起始
        int[] tmp = new int[end-start+1];
        int k = 0;
        for(k=start;k<=end;k++){
            tmp[k] =arr[k];
        }
        for
(k=start;k<end;k++){ if(i>mid){ arr[k]=tmp[j++]; }else if(j>end){ arr[k] = tmp[i++]; }else if(tmp[i]>tmp[j]){ arr[k] = tmp[j++]; }else{ arr[k] = tmp[i++]; } } }

或許有人問:不是兩個有序陣列的排序嗎?怎麼只有一個數據源?這很簡單,我們的最終目的是排序一個數組,所以我們最終也是在一個數組中模擬兩個有序陣列,並且進行歸併,那麼,用什麼來劃分呢?細看上面程式碼,你就發現啦。就是我們的索引。那麼,如何確定我們的索引呢?這就要和實際情況相關了。話不多說,即可走起!

自頂而下的歸併排序實現

/*
*自頂而下的歸併排序實現
*arr 資料來源
*start 排序起點
*end   排序終點
*/
public static void msort(int[] arr,int start,int end){
        if(start>=end){
        return ;
        }
        int mid = (end+start)/2;   //確定mid值(每次折半)
        msort(arr,start,mid);      //左邊排序
        msort(arr,mid+1,end);      //右邊排序
        merge(arr,start,mid,end); //呼叫底板排序
}

自底向上的歸併排序實現

/*
*自底向上的歸併排序實現
*arr 資料來源
*/
public static void msort(int []arr){
        int size = a.length;
        int start,length;
        for(length=1;length<size;length*=2){
            for(start = 0;start <size-length;start+=length*2){
                //因為每次都是取2作為一個數組
                //同時每次取兩個相鄰陣列進行排序,所以mid等於初始位置+一個數組的長度-1
                int mid = start+length-1;
                int end = (start+length*2-1)<(size-1)?start+length*2-1:size-1;
                merge(arr,start,mid,end);
            }
        }
}

總的來說,這兩種方法其實各有利弊,前者易懂,但程式碼較多,運算速度可能不及後者。但後者程式碼晦澀難懂,用起來比較燒腦。所以,選擇的時候,就要根據自己的實際理解情況啦。
排序算法系列結束
下一章:單例模式的實現