歸併排序解剖

歸併排序

歸併排序描述

歸併排序(MERGE-SORT是建立在歸併操作上的一種有效的排序算法,該算法是採用分治法(Divideand Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。

若將兩個有序表合併成一個有序表,稱爲二路歸併

算法思想

1、劃分:將待排序序列劃分爲兩個長度相等的子序列。

2、求解子問題:分別對這兩個子序列進行歸併排序,得到兩個有序子序列。

3、合併:將兩個有序子序列合併成一個有序序列。

算法核心步驟

核心步驟就一下三步:

1、歸併排序前半個子序列

2、歸併排序後半個子序列

3、合併兩個已排序的子序列

其中,前兩個步驟的是一樣的方法mergeSort()進行遞歸,第三步是另一個方法merge()。這個算法中基本的操作就是第三步合併兩個已排序的表。因爲這兩個表是已排序的,所以若將輸出放到第三個表中,則該算法可以通過對輸入數據一趟排序來完成。基本的合併算法是取兩個輸入數組A和B,一個輸出數組C,以及3個計數器Actr、Bctr、Cctr,它們初始置於對應數組的開始端。A[Actr]和B[Bctr]中較小者被拷貝到C中的下一個位置,相關的計數器向前推進一步。當兩個輸入表有一個用完的時候,則將另一個表中剩餘部分拷貝到C中。

實現代碼(Java)

 

/**
 * 歸併排序
 * @author 卡羅-晨
 *
 */
public class MergeSort {
	
	/**
	 * 歸併排序之進行遞歸調用
	 * @param a	可比較的數組
	 * @param tmpArray 存放每次遞歸結束之後的結果,有序集
	 * @param left 數組最左邊的下標
	 * @param right 數組最右邊的下標
	 */
	private static <T extends Comparable<? super T>> void mergeSort(
			T[] a,T[] tmpArray,int left,int right) {
		if(left<right) {
			int center = (left+right)/2;
			mergeSort(a, tmpArray, left, center); //歸併排序前半個子序列
			mergeSort(a, tmpArray, center+1, right); //歸併排序後半個子序列
			merge(a,tmpArray,left,center+1,right); //合併兩個已排序的子序列
		}
	}
	
	/**
	 * 歸併排序之合併序列的左右兩半
	 * @param a 可比較的數組
	 * @param tmpArray 存放每次遞歸結束之後的結果,有序集
	 * @param leftPos 左半邊開始下標
	 * @param rightPos 右半邊開始下標
	 * @param rightEnd 右半邊結束下標
	 */
	private static <T extends Comparable<? super T>> void merge(
			T[] a, T[] tmpArray, int leftPos, int rightPos, int rightEnd) {
		int leftEnd = rightPos-1;
		int tmpPos = leftPos;
		int numElements = rightEnd-leftPos+1;
		
		while(leftPos<=leftEnd && rightPos<=rightEnd) {
			if(a[leftPos].compareTo(a[rightPos])<=0) {
				tmpArray[tmpPos++] = a[leftPos++];
			}else {
				tmpArray[tmpPos++] = a[rightPos++];
			}
		}
		while(leftPos<=leftEnd) {
			tmpArray[tmpPos++] = a[leftPos++];
		}
		while(rightPos<=rightEnd) {
			tmpArray[tmpPos++] = a[rightPos++];
		}
		
		for(int i=0;i<numElements;i++,rightEnd--) {
			a[rightEnd] = tmpArray[rightEnd];
		}
	}
	
	/**
	 * 歸併排序
	 * @param a待排序序列
	 */
	public static <T extends Comparable<? super T>> void mergeSort(T[] a){
		T[] tmpArray = (T[]) new Comparable[a.length];
		mergeSort(a, tmpArray, 0, a.length-1);
	}
}

merge()方法很精巧。如果對merge的每個遞歸調用均局部聲明一個臨時數組,那麼在任一時刻就可能有個臨時數組處在活動期。精密的考察表明,由於merge是mergeSort的最後一行,因此在任一時刻只需要一個臨時數組在活動,而且這個臨時數組可以在public型的mergeSort驅動程序中建立。

算法分析

二路歸併排序的時間代價是O(nlogn)。二路歸併排序在合併過程中需要與原始記錄序列同樣數量的存儲空間,因此其空間複雜性爲O(n)

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