一、歸併排序簡介(自己理解)
自己的理解一句話:所謂歸併排序,就是遞歸+合併。
引用百度百科對歸併排序的定義:是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。點擊打開鏈接
二、歸併排序過程
過程:首先對數組進行無限對半分割,不斷調用自身函數,也成遞歸。每次分割得到左右兩個數組,對兩邊的數組分別進行排序,等到兩邊的數組都有序後,利用封裝的merge函數對兩個有序數組進行合併,最後得到整體有序。
其中無限分割最後應該分割到左右數組各只有一個元素,然後對兩邊的元素進行合併,再返回上層再合併。最終回到初始的數組上。
圖解過程:
首先第一次分割,得到 [ 5 , 7 , 4 , 11 ] , [ 2 , 8 , 2 , 15 ] 兩個數組,再往下分割,直至左右兩個數組只有一個元素
分割完成後,對左右兩邊進行合併。
初始思路:新建一個數組,長度定義與原數組相同,定義三個指針,分別指向左數組第一個元素,右數組第一個元素和新定義數組的第一個元素,對原數組左右兩部分分別遍歷,想得到的較小的數傳入新數組。最後將新數組的數據全部拷貝到原數組中。合併完成。
三、代碼實現(Java)
public class MergeSort {
public static void main(String[] args) {
//獲取指定長度的數組,getArray是自己封裝的一個函數
long[] arr1 = getArray(50000,500000);
//獲取兩個時間相減,得到排序消耗的時間
long startTime = new Date().getTime();
mergeSort(arr1,0,arr1.length - 1);
long endTime = new Date().getTime();
int time = (int)(endTime - startTime);
//打印數組
printArray(arr1);
System.out.println("\n" + time + "ms");
}
//歸併排序的公共方法
public static void mergeSort(long[] arr, int l, int r) {
// TODO Auto-generated method stub
long[] temp = new long[arr.length];
_mergeSort(arr, l, r, temp);
}
//歸併排序的私有方法
private static void _mergeSort(long[] arr, int l, int r, long[] temp) {
// TODO Auto-generated method stub
if(r <= l) {
return;
}
int mid = (l + r) / 2;
_mergeSort(arr, l, mid, temp); //左邊排序
_mergeSort(arr, mid + 1, r, temp); //右邊排序
merge(arr,l, mid, r, temp);
}
//合併兩個有序數組arr[l,mid],arr[mid+1,r]
private static void merge(long[] arr, int l, int mid, int r, long[] temp) {
// TODO Auto-generated method stub
int index, index1, index2;
index = 0;
index1 = l;
index2 = mid + 1;
while(index < r - l + 1) {
if(index1 > mid) {
temp[index ++] = arr[index2 ++];
}else if(index2 > r) {
temp[index ++] = arr[index1 ++];
}else if(arr[index1] < arr[index2]) {
temp[index ++] = arr[index1 ++];
}else {
temp[index ++] = arr[index2 ++];
}
}
for(int i = 0; i < r - l + 1; i ++) {
arr[i + l] = temp[i];
}
}
}
四、代碼運行結果
1、對50000個元素的數組進行排序
平均耗時:15ms
2、對500000個元素的數組進行排序
平均耗時:100ms
3、對5000000個元素的數組進行排序
平均耗時:1010ms
五、時間複雜度
歸併排序屬於較穩定且較高效算法
時間複雜度爲:O(N*logN)
六、總結
歸併排序相比較選擇排序,直接插入排序和冒泡排序的效率要高的多,不過代碼中還有很多值得優化的地方。例如:應該在調用私有函數前創建一個公共的副本數組,這樣就不用每次遞歸都new一個新的數組,節省資源,效率稍微高一點。