簡單排序算法實現——歸併排序

歸併排序(Merge Sort) 是一種採用了分治(Divide and Conquer) 想法的排序算法。


該算法中基本的操作是合併兩個已經排序的表,並將輸出放到第三個表中,該過程可以通過對輸入數據一趟排序來完成。

基本的合併算法是取兩個輸入數組A和B,一個輸出數組C,與三個計數器Actr,Bctr,Cctr,它們初始置於對應數組的開始端。

A[Actr]和B[Bctr]中的較小者被複制到C中的下一個操作位置,相關的Actr或Bctr向前推進一步。

當兩個輸入表中有一個用完的時候,則將另一個表中剩餘部分拷貝到C中。

合併兩個已排序的表的時間顯然是線性的,因爲最多進行N-1次比較。


這一過程體現的是"治"的思想,該部分的java代碼實現如下,數組A與數組B在概念上被leftPos,leftEnd,rightPos,rightEnd四個下標標定,數組C是一開始在下面會提到的public驅動方法裏創建的tmpArray數組。 tmpArray裏的操作位置由下標tmpPos標定,該下標與前四個下標無關獨立,是始終遞增的下標。

	private static <AnyType extends Comparable<? super AnyType>>
	void Merge(AnyType[] a, AnyType[] tmpArray, int leftPos, int rightPos, int rightEnd){
		int leftEnd=rightPos-1;//通過該步計算得出A數組的結束位置,由此4個下標完全指定AB數組
		int tmpPos=leftPos;//該下標指定temp數組操作位置,始終遞增.
		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++];
		}
		
		//B數組已經用盡,A數組有剩餘
		while(leftPos<=leftEnd){
			tmpArray[tmpPos++]=a[leftPos++];
		}
		
		//A數組已經用盡,B數組有剩餘
		while(rightPos<=rightEnd){
			tmpArray[tmpPos++]=a[rightPos++];
		}
		
		for(int i=0;i<numElements;i++,rightEnd--)
			a[rightEnd]=tmpArray[rightEnd];
	}


對於一開始的“分”的過程,可以用以下代碼實現:

	private static <AnyType extends Comparable<? super AnyType>>
	void MergeSort(AnyType[] a, AnyType[] tmpArray, int left, int right){
		//當left==right的時候,
		//已經劃分到單個元素的基本情況,無需再分,可遞歸返回執行merge操作
		if(left<right){
			int center=(left+right)/2;
			//對left~center,center+1~right 再進行細分。
			MergeSort(a,tmpArray,left,center);
			MergeSort(a,tmpArray,center+1,right);
			
			//left是A數組的開始下標,center+1是B數組開始下標,right是B數組結束下標
			//實際上在Merge中通過計算還要得到一個A數組的結束下標。
			Merge(a,tmpArray,left,center+1,right);
		}
	}
整體的可再分的一個判斷條件是left<right,當該條件不滿足,即left==right時,表明已經分到了最基本的單個元素的情況,此時遞歸棧開始返回,各個階段的Merge操作被執行。在每一步的MergeSort階段並沒有做實際的數組操作,因此MergeSort的唯一作用是不斷地判定left,center,right的值,將數組在邏輯概念上不斷二分,但是知道遞歸棧返回執行Merge方法之前,數組都沒有實際的變化。


以上的方法都是private的,唯一暴露在外的public方法用作以驅動,在該方法中要構建一個tmpArray輔助數組,作爲臨時的C數組被使用。

另外,a,tmpArray都是採用傳引用方法被傳遞的,因此都在同一塊內存上操作,每Merge完一次,數組a都會有實際的變化。

public驅動方法代碼如下:

public class MergeSort{	
	public static <AnyType extends Comparable<? super AnyType>>
	void MergeSort(AnyType[] a){
		AnyType[] tmpArray=(AnyType[]) new Comparable[a.length];
		
		MergeSort(a,tmpArray,0,a.length-1);
}


歸併算法的平均時間複雜度爲O(nlogn).

附圖一張,以供理解記憶:





發佈了30 篇原創文章 · 獲贊 9 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章