(四)算法學習之歸併排序

一、歸併排序簡介(自己理解)

自己的理解一句話:所謂歸併排序,就是遞歸+合併。

引用百度百科對歸併排序的定義:是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法(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一個新的數組,節省資源,效率稍微高一點。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章