歸併排序(Merge sort)是創建在歸併操做上的一種有效的排序算法,指的是將兩個已經排序的序列合併成一個序列的操做。該算法是採用分治法(Divide and Conquer)的一個很是典型的應用。html
做爲一種典型的分而治之思想的算法應用,歸併排序的實現由兩種方法:git
1. 從下往上的歸併排序【迭代】:github
經過分治法將長度爲n的序列劃分爲n個長度爲1的子序列。 算法
進行兩兩歸併比較,獲得 n/2 個長度爲 2 的有序子序列 數組
重複第 2 步,直到全部子序列歸併成一個長度爲 n 的有序序列。數據結構
2. 從上往下的歸併排序【遞歸】:ide
分解 -- 將當前區間一分爲二,即求分裂點 mid = (low + high)/2; post
求解 -- 遞歸地對兩個子區間a[low...mid] 和 a[mid+1...high]進行歸併排序。遞歸的終結條件是子區間長度爲1。性能
合併 -- 將已排序的兩個子區間a[low...mid]和 a[mid+1...high]歸併爲一個有序的區間a[low...high]。
學習
3. 歸併步驟:
申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列;
設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置;
比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置;
重複步驟 3 直到某一指針達到序列尾;
將另外一序列剩下的全部元素直接複製到合併序列尾。
歸併排序的效率是比較高的,設數列長爲N,將數列分開成小數列一共要 logN 步,每步都是一個合併有序數列的過程,時間複雜度能夠記爲O(N),故一共爲O(N*logN),故時間複雜度爲O(nlogn)。
歸併排序過程當中,須要一個輔助空間來暫存兩有序子文件歸併的結果,所以空間複雜度爲O(n)。
歸併是穩定的算法,在分解和並歸過程當中元素相對順序未發生改變。
不能歸位
public class MergeSort { // 歸併排序(從上往下,遞歸) public static void mergeSortUp2Down(int [] arr, int start, int end){ if(arr!=null && start<end){//當子序列中只有一個元素時結束遞歸 int mid=(start+end)/2;//劃分子序列 mergeSortUp2Down(arr, start, mid);//對左側子序列進行遞歸排序 mergeSortUp2Down(arr, mid+1, end);//對右側子序列進行遞歸排序 merge(arr, start, mid, end);//合併 } } //歸併排序(從下往上,迭代) public static void mergeSortDown2Up(int [] arr){ if(arr!=null){ int len = arr.length; //gap表示有序數組的長度(1,2,4,8……) for(int gap = 1; gap < len; gap*=2){ int i; // 將"每2個相鄰的子數組" 進行合併排序。 for(i = 0; i+2*gap-1 < len; i+=(2*gap)){ merge(arr, i, i+gap-1, i+2*gap-1); } // 若 i+gap-1 < len-1,則剩餘一個子數組沒有配對。 // 將該子數組合併到已排序的數組中。 if (i+gap-1 < len-1){ merge(arr, i, i+gap-1, len-1); } } } } //兩路歸併算法,兩個排好序的子序列合併爲一個子序列 public static void merge(int []arr, int left, int mid, int right){ int []tmp=new int[arr.length];//輔助數組 int p1=left,p2=mid+1,k=left;//p一、p2是檢測指針,k是存放指針 while(p1<=mid && p2<=right){ if(arr[p1]<=arr[p2]) tmp[k++]=arr[p1++]; else tmp[k++]=arr[p2++]; } while(p1<=mid) tmp[k++]=arr[p1++];//若是第一個序列未檢測完,直接將後面全部元素加到合併的序列中 while(p2<=right) tmp[k++]=arr[p2++];//同上 //複製回原素組 for (int i = left; i <=right; i++) arr[i]=tmp[i]; } public static void main(String[] args){ int[] arr = { 49, 38, 65, 97, 76, 13, 27, 50 }; //mergeSortUp2Down(arr, 0, a.length-1); mergeSortDown2Up(arr); System.out.println("排好序的數組:"); for (int e : arr) System.out.print(e+" "); } }