歸併排序是分治演算法的另乙個典型的體現。與快速排序一樣,它依賴資料之間的比較進行排序。
其缺點是需要額外的空間來輔助排序的過程。這使得歸併排序的實用性大大降低,因為在日常的應用中,使用歸併排序的場景都可以使用快速排序來替代。但是它的優點是可以按照預期來切分陣列,每一次都可以對半分,這樣不會出現因為分割陣列不均勻而使遞迴呼叫變成乙個斜向二叉樹,在處理大量資料的情況下,這個優點變得非常受青睞。
歸併排序的原理大概如下:
將給定的亂序陣列平均分割成兩個子陣列
重複第一步,直到每個小陣列只剩下1個數
將相鄰的兩個子陣列進行合併;合併的過程是:從開始遍歷兩個子陣列,哪個陣列的數值小就取哪個,直到遍歷完成
重複第三步,直到所有的子陣列合併完成
陣列有序
簡單的原理展示如下:
下面的圖詳細展示了當 n=16 時,歸併算法子陣列的依賴樹
演算法實現如下:
void merge(int *a, int *aux, int lo, int mid, int hi)
}void merge_sort(int *a, int *aux, int lo, int hi)
對於上面的實現,是已經優化過一次的。優化的點在於:一次性需要申請乙個 同原陣列一樣大小的輔助陣列 aux。然後將 aux 傳入每一次遞迴裡面,這樣,就不需要在每一次 merge 函式中進行申請陣列的行為。
如果不這樣做的話,那演算法的大部分時間,其實是消耗在了輔助陣列的申請上。
用不同的排序方法處理小規模問題,能改進大多數遞迴演算法的效能,這是遞迴在小規模問題中呼叫太過頻繁。同 快速排序 一樣,在歸併排序處理小陣列問題的時候,使用插入排序來替代小規模排序可以提高一些效能。
對merge_sort
改進如下:
void merge_sort(int *a, int *aux, int lo, int hi)
int mid = lo + (hi - lo) / 2;
merge_sort(a, aux, lo, mid); // 排序 左邊子陣列
merge_sort(a, aux, mid+1, hi); // 排序 右邊子陣列
merge(a, aux, lo, mid, hi); // 合併兩個子陣列
}
如果我們可以判斷 兩個子陣列已經是有序的話,就可以跳過 merge 函式,這樣任意有序的陣列演算法的執行時間就是線性的了。
改動merge_sort
函式如下:
void merge_sort(int *a, int *aux, int lo, int hi)
int mid = lo + (hi - lo) / 2;
merge_sort(a, aux, lo, mid); // 排序 左邊子陣列
merge_sort(a, aux, mid+1, hi); // 排序 右邊子陣列
if(a[mid] <= a[mid+1]) return;
merge(a, aux, lo, mid, hi); // 合併兩個子陣列
}
要做到這一點,需要一點技巧,我們需要在遞迴呼叫的每乙個層次替換輔助函式的角色。來達到這一點。
**實現如下:
void merge(int *src, int *dst, int lo, int mid, int hi)
}void merge_sort(int *src, int *dst, int lo, int hi)
#define ssize 5
int main() , aux[ssize];
memcpy(aux, a, sizeof(int)*ssize);
merge_sort(aux, a, 0, 4);
return 0;
}
上面的實現,通過兩個引數 src 和 dst,對於函式merge_sort
來說,每一層的 src 和 dst 都是相互交換過的。這樣 每一層所依賴的src,其實是上一層呼叫的dst,這樣就省去了每一次都複製一遍陣列的過程了。
需要注意的是:雖然,在大部分應用的時候,歸併排序都能被快速排序替代。但是在一些場景下,優化過的歸併排序還是非常具有吸引力的。在呼叫 merge_sort 之前,輔助陣列需要和原始陣列有一樣的資料。這裡,我們使用memcpy進行拷貝,提高效率。
排序演算法系列之歸併排序
public class mergesort if index1 middle while index2 high else while index1 middle 將temp low high 序列複製到原序列 system.arraycopy temp,low,array,low,high 1 ...
排序演算法系列 1 歸併排序
知識點 歸併排序 歸併排序是建立在歸併操作上的一種有效的排序演算法。該演算法是採用分治法 divide and conquer 的乙個非常典型的應用。歸併排序是一種穩定的排序方法。將已有序的子串行合併,得到完全有序的序列 即先使每個子串行有序,再使子串行段間有序。若將兩個有序表合併成乙個有序表,稱為...
歸併排序(重溫經典演算法系列)
單個元素肯定有序 歸併排序採用分治思想,分而治之 將待排序陣列劃分為n等分,每份長度為1個元素,則 n份全部有序 再一生二,二生四,逐步兩兩元素有序的區間,歸一合併成1個有序區間 最終會歸併出整乙個陣列元素有序的結果.歸併排序有兩種實現方式 1 自頂向下遞迴呼叫實現 2 自底向上迭代執行實現.左右雙...