歸併排序(Merging Sort)就是利用歸併的思想實現的排序方法。它的原理是假設初始序列含有n個記錄,則能夠當作是n個有序的子序列,每一個子序列的長度爲1,而後兩兩歸併,獲得[n/2]個長度爲2或1的有序子序列,再兩兩歸併,直至獲得一個長度爲n的有序序列爲止,這種排序方法成爲2路歸併排序。java
package Sort; class MergeSort { public static void main(String[] args) { int[] list = {80,40,50,30,60,70,10,90,20};; MergeSort ms = new MergeSort(); ms.MSort(list); System.out.println(""); System.out.println("最終結果:"); ms.printArrry(list); } private void printArrry(int[] a){ for(int k = 0; k <= a.length-1; k++){ System.out.print(a[k]); } } private void MSort(int[] list) { mergeSort(list, 0, list.length-1); } private void mergeSort(int [] list,int a, int b){ int mid; if (a == b){ //System.out.println("執行到最底層:"); //printArrry(list); return; } else { mid = (a+b)/2; mergeSort(list, a, mid); mergeSort(list, mid+1, b); Merge(list, a, mid, b); System.out.println("\n"+"left:"+a+" mid:"+mid+" right:"+b); System.out.println("此時數組爲:"); printArrry(list); } } private void Merge(int [] list, int left, int mid, int right){ int a,b,c,d; a = left; b = mid+1; c = left; d = left; int[] tempaddr = new int[list.length]; while (a<=mid && b<=right) { if (list[a] <= list[b]) { tempaddr[c++] = list[a++]; } else { tempaddr[c++] = list[b++]; } } while (a<=mid) { tempaddr[c++] = list[a++]; } while (b<=right) { tempaddr[c++] = list[b++]; } while (d <= right){ list[d] = tempaddr[d++]; } } }
private void mergeSort(int [] list,int a, int b){ int mid; /*當拆分至最小單元時,則跳出*/ if (a == b){ return; } else { mid = (a+b)/2; /*將上一次拆分後的數組list的前半部分再進行拆分*/ mergeSort(list, a, mid); /*將上一次拆分後數組list的後半部分再進行拆分*/ mergeSort(list, mid+1, b); /*將拆分至list最小單元的前半部分和後半部分進行歸併*/ Merge(list, a, mid, b); System.out.println("\n"+"left:"+a+" mid:"+mid+" right:"+b); System.out.println("此時數組爲:"); printArrry(list); } }
private void Merge(int [] list, int left, int mid, int right){ int a,b,c,d; a = left; b = mid+1; c = left; d = left; int[] tempaddr = new int[list.length]; /*將兩個有序的數組,從頭開始比較,較小值存入tempaddr[]*/ while (a<=mid && b<=right) { if (list[a] <= list[b]) { tempaddr[c++] = list[a++]; } else { tempaddr[c++] = list[b++]; } } /*將前半部分還有剩餘的數組取出,存入tempaddr[]*/ while (a<=mid) { tempaddr[c++] = list[a++]; } /*將後半部分還有剩餘的數組取出,存入tempaddr[]*/ while (b<=right) { tempaddr[c++] = list[b++]; } /*將已經歸併好的數組,傳給list,使得list原有的對應於list[left..right]的部分有序*/ while (d <= right){ list[d] = tempaddr[d++]; } }
left:0 mid:0 right:1 此時數組爲: 408050306070109020 left:0 mid:1 right:2 此時數組爲: 405080306070109020 left:3 mid:3 right:4 此時數組爲: 405080306070109020 left:0 mid:2 right:4 此時數組爲: 304050608070109020 left:5 mid:5 right:6 此時數組爲: 304050608010709020 left:7 mid:7 right:8 此時數組爲: 304050608010702090 left:5 mid:6 right:8 此時數組爲: 304050608010207090 left:0 mid:4 right:8 此時數組爲: 102030405060708090 最終結果: 102030405060708090
紅色部分顯示的是,此時操做的數組的區間,黑色部分,則是未被操做的區間。c++
經過這張圖能夠看出,由於mid=(a+b)/2,mergeSort(list, a, mid),因此list數組一路向下拆分,從0-8,到0-4,到0-2,到0-1,最後到0-0,此時獲得return,返回遞歸上一層,此時mid爲0,mergeSort(list, mid+1, b),也能夠獲得return,而後就執行Merge(list, a, mid, b)。這句話就是把此時(a,mid,b)=(0,0,1)進行了歸併,使得list[0..1]有順序。數組
以此類推,接下來依次是(a,mid,b)=(0,1,2),(a,mid,b)=(0,2,4),....,(a,mid,b)=(5,6,8),(a,mid,b)=(0,4,8)spa
將list[1..n]的相鄰長度爲h的有序序列進行兩兩歸併,並將結果放回list[1..n],須要耗時O(N)的時間,由徹底二叉樹的深度剋制,整個排序須要進行log2N次,因此總的時間複雜度爲O(nlogn)。這比上一篇講的冒泡排序,直選排序都要快速,因此應用範圍也更爲普遍。blog