歸併排序(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).
附圖一張,以供理解記憶: