歸併排序詳述(程式碼+圖解)
阿新 • • 發佈:2018-11-24
我是看了這一篇部落格的圖+一篇部落格的程式碼看明白的~~現在把這兩個合在一起了,感謝博主
以下轉載自->部落格連結
圖解排序演算法(四)之歸併排序
基本思想
歸併排序(MERGE-SORT)是利用歸併的思想實現的排序方法,該演算法採用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然後遞迴求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。
分而治之
可以看到這種結構很像一棵完全二叉樹,本文的歸併排序我們採用遞迴去實現(也可採用迭代的方式去實現)。分
合併相鄰有序子序列
再來看看治階段,我們需要將兩個已經有序的子序列合併成一個有序序列,比如上圖中的最後一次合併,要將[4,5,7,8]和[1,2,3,6]兩個已經有序的子序列,合併為最終序列[1,2,3,4,5,6,7,8],來看下實現步驟。
以下轉載自->部落格連結
/** * 歸併排序:C 語言 * * @author skywang * @date 2014/03/12 */ #include <stdio.h> #include <stdlib.h> // 陣列長度 #define LENGTH(array) ( (sizeof(array)) / (sizeof(array[0])) ) /* * 將一個數組中的兩個相鄰有序區間合併成一個 * * 引數說明: * a -- 包含兩個有序區間的陣列 * start -- 第1個有序區間的起始地址。 * mid -- 第1個有序區間的結束地址。也是第2個有序區間的起始地址。 * end -- 第2個有序區間的結束地址。 */ void merge(int a[], int start, int mid, int end) { int *tmp = (int *)malloc((end-start+1)*sizeof(int)); // tmp是彙總2個有序區的臨時區域 int i = start; // 第1個有序區的索引 int j = mid + 1; // 第2個有序區的索引 int k = 0; // 臨時區域的索引 while(i <= mid && j <= end) { if (a[i] <= a[j]) tmp[k++] = a[i++]; else tmp[k++] = a[j++]; } while(i <= mid) tmp[k++] = a[i++]; while(j <= end) tmp[k++] = a[j++]; // 將排序後的元素,全部都整合到陣列a中。 for (i = 0; i < k; i++) a[start + i] = tmp[i]; free(tmp); } /* * 歸併排序(從上往下) * * 引數說明: * a -- 待排序的陣列 * start -- 陣列的起始地址 * endi -- 陣列的結束地址 */ void merge_sort_up2down(int a[], int start, int end) { if(a==NULL || start >= end) return ; int mid = (end + start)/2; merge_sort_up2down(a, start, mid); // 遞迴排序a[start...mid] merge_sort_up2down(a, mid+1, end); // 遞迴排序a[mid+1...end] // a[start...mid] 和 a[mid...end]是兩個有序空間, // 將它們排序成一個有序空間a[start...end] merge(a, start, mid, end); } /* * 對陣列a做若干次合併:陣列a的總長度為len,將它分為若干個長度為gap的子陣列; * 將"每2個相鄰的子陣列" 進行合併排序。 * * 引數說明: * a -- 待排序的陣列 * len -- 陣列的長度 * gap -- 子陣列的長度 */ void merge_groups(int a[], int len, int gap) { int i; int twolen = 2 * gap; // 兩個相鄰的子陣列的長度 // 將"每2個相鄰的子陣列" 進行合併排序。 for(i = 0; i+2*gap-1 < len; i+=(2*gap)) { merge(a, i, i+gap-1, i+2*gap-1); } // 若 i+gap-1 < len-1,則剩餘一個子陣列沒有配對。 // 將該子數組合併到已排序的陣列中。 if ( i+gap-1 < len-1) { merge(a, i, i + gap - 1, len - 1); } } /* * 歸併排序(從下往上) * * 引數說明: * a -- 待排序的陣列 * len -- 陣列的長度 */ void merge_sort_down2up(int a[], int len) { int n; if (a==NULL || len<=0) return ; for(n = 1; n < len; n*=2) merge_groups(a, len, n); } void main() { int i; int a[] = {80,30,60,40,20,10,50,70}; int ilen = LENGTH(a); printf("before sort:"); for (i=0; i<ilen; i++) printf("%d ", a[i]); printf("\n"); merge_sort_up2down(a, 0, ilen-1); // 歸併排序(從上往下) //merge_sort_down2up(a, ilen); // 歸併排序(從下往上) printf("after sort:"); for (i=0; i<ilen; i++) printf("%d ", a[i]); printf("\n"); }