1、基本思想數組
歸併排序,將當前序列分紅若干個小的有序序列,而後逐個合併成更大的有序序列。這裏所謂的若干個小的有序序列便是將序列分割成n個長度爲1的序列,而後兩兩合併成長度爲二的有序序列。而後在將這長度爲二的有序序列合併爲長度爲四的有序序列。依次類推,最終達到原序列長度,這樣,排序就完成了。這實際上是歸併排序遞歸回溯過程的描述。歸併排序的正序描述能夠是這樣,將序列分紅兩個子序列,對兩個子序列進行歸併排序,而後將兩個子序列合併到原序列中。dom
2、實現步驟測試
歸併排序,有兩個須要解決的問題:1、如何劃分子區間。2、如何合併子區間。spa
劃分子區間:code
這裏採用兩路歸併排序,即將當前序列劃分紅兩個子序列。blog
合併子區間:排序
因爲子區間是有序的,因此在合併過程當中不會有很大的複雜度,一次遍歷便可。遞歸
思想已經陳述完畢,下面看代碼,有詳細註釋。get
3、實現代碼io
隨機數組測試類 點擊這裏
package sort; import sort.util.*; public class MergingSort implements ISort{ //private static int[] c = null; //將有序序列a[left] ~ a[middle]和a[middle+1] ~ a[right]合併到數組b中,返回數組b private void merge(int[] a , int left , int middle , int right) { int[] b = new int[a.length]; for(int i = 0; i < a.length; i++) { //將數組a複製到b中 b[i] = a[i]; } int i = left , j = middle + 1 , k = left; while(i <= middle && j <= right) { //合併過程,選擇較小的,逐個賦值。 if(b[i] < b[j]) a[k++] = b[i++]; else a[k++] = b[j++]; } //循環結束,說明有一個有序序列已經遍歷完畢 while(i <= middle) {a[k++] = b[i++];} //將剩餘的部分直接複製到a數組中 while(j <= right) {a[k++] = b[j++];} //這兩個循環只有一個能被執行 } //對a[left] ~ a[right]進行歸併排序,排序後的結果放在b[]中 private void mergeSort(int[] a , int left , int right) { if(left != right) { //當進行歸併排序的數組只有一個元素 int middle = (left + right) / 2; //劃分紅兩部分進行歸併 mergeSort(a , left , middle); //左邊部分進行歸併排序 mergeSort(a , middle+1 , right); //右邊部分進行歸併排序 merge(a , left , middle , right); //左右排序完成後進行合併 } } public void sort(int[] array){ mergeSort(array , 0 , array.length-1); } public static void main(String[] args) { int[] array = RandomArrayGenerator.getRandomArray(100 , 30); SortTestHelper.test(new MergingSort() , array); } }
測試結果:
4、總結分析
時間複雜度:O(n log n) 合併複雜度爲n,遞歸過程的複雜度爲log2n
空間複雜度:O(n) 須要一個輔助數組
穩定性:穩定。
八大排序中其他兩個nlogn複雜度的堆排序和快速排序是不穩定的,較普通排序更快的希爾排序也是不穩定的。本文所講的歸併排序倒是穩定的,並且效率也很可觀。
本文我的編寫,水平有限,若有錯誤,懇請指出,歡迎討論分享