知識點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);
            }
        }
}

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

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