歸併排序 (merge sort) 是一類與插入排序、交換排序、選擇排序不一樣的另外一種排序方法。歸併的含義是將兩個或兩個以上的有序表合併成一個新的有序表。歸併排序有多路歸併排序、兩路歸併排序 , 可用於內排序,也能夠用於外排序。這裏僅對內排序的兩路歸併方法進行討論。java
1、兩路歸併排序算法思路算法
分而治之(divide - conquer);每一個遞歸過程涉及三個步驟
第一, 分解: 把待排序的 n 個元素的序列分解成兩個子序列, 每一個子序列包括 n/2 個元素.
第二, 治理: 對每一個子序列分別調用歸併排序MergeSort, 進行遞歸操做
第三, 合併: 合併兩個排好序的子序列,生成排序結果.數組
2、算法實現
此算法的實現不像圖示那樣簡單,現分三步來討論。首先從宏觀上分析,首先讓子表表長 L=1 進行處理;不斷地使 L=2*L ,進行子表處理,直到 L>=n 爲止,把這一過程寫成一個主體框架函數 mergesort 。而後對於某肯定的子表表長 L ,將 n 個記錄分紅若干組子表,兩兩歸併,這裏顯然要循環若干次,把這一步寫成一個函數 mergepass ,可由 mergesort 調用。最後再看每一組(一對)子表的歸併,其原理是相同的,只是子表表長不一樣,換句話說,是子表的首記錄號與尾記錄號不一樣,把這個歸併操做做爲核心算法寫成函數 merge ,由 mergepass 來調用。假設咱們有一個沒有排好序的序列,那麼首先咱們使用分割的辦法將這個序列分割成一個一個已經排好序的子序列,而後再利用歸併的方法將一個個的子序列合併成排序好的序列。分割和歸併的過程能夠看下面的圖例。框架
3、代碼實現ide
public static int[] sort(int[] a,int low,int high){ int mid = (low+high)/2; if(low<high){ sort(a,low,mid); sort(a,mid+1,high); //左右歸併 merge(a,low,mid,high); } return a; } public static void merge(int[] a, int low, int mid, int high) { int[] temp = new int[high-low+1]; int i= low; int j = mid+1; int k=0; // 把較小的數先移到新數組中 while(i<=mid && j<=high){ if(a[i]<a[j]){ temp[k++] = a[i++]; }else{ temp[k++] = a[j++]; } } // 把左邊剩餘的數移入數組 while(i<=mid){ temp[k++] = a[i++]; } // 把右邊邊剩餘的數移入數組 while(j<=high){ temp[k++] = a[j++]; } // 把新數組中的數覆蓋nums數組 for(int x=0;x<temp.length;x++){ a[x+low] = temp[x]; } }
4、算法分析函數
(1)穩定性
歸併排序是一種穩定的排序。
(2)存儲結構要求
可用順序存儲結構。也易於在鏈表上實現。
(3)時間複雜度
對長度爲n的文件,需進行趟二路歸併,每趟歸併的時間爲O(n),故其時間複雜度不管是在最好狀況下仍是在最壞狀況下均是O(nlgn)。
(4)空間複雜度
須要一個輔助向量來暫存兩有序子文件歸併的結果,故其輔助空間複雜度爲O(n),顯然它不是就地排序。
注意:
若用單鏈表作存儲結構,很容易給出就地的歸併排序spa