1.兩路歸併排序算法思路
①把 n 個記錄看成 n 個長度爲1的有序子表;
②進行兩兩歸併使記錄關鍵字有序,得到 n/2 個長度爲 2 的有序子表;
③重複第②步直到所有記錄歸併成一個長度爲 n 的有序表爲止。
【例】 有一組關鍵字 {4,7,5,3,2,8,6,1},n=8, 將其按由小到大的順序排序。 兩路歸併排序操作過程如圖 9.12 所示,其中i 爲子表長度。
2.算法實現
此算法的實現不像圖示那樣簡單,現分三步來討論。首先從宏觀上分析,首先讓子表表長 L=1 進行處理;不斷地使 L=2*L ,進行子表處理,直到 L>=n 爲止,把這一過程寫成一個主體框架函數 mergesort
。然後對於某確定的子表表長 L ,將 n 個記錄分成若干組子表,兩兩歸併,這裏顯然要循環若干次,把這一步寫成一個函數 mergepass ,可由 mergesort 調用。最後再看每一組(一對)子表的歸併,其原理是相同的,只是子表表長不同,換句話說,是子表的首記錄號與尾記錄號不同,把這個歸併操作作爲核心算法寫成函數 merge ,由 mergepass 來調用。假設我們有一個沒有排好序的序列,那麼首先我們使用分割的辦法將這個序列分割成一個一個已經排好序的子序列,然後再利用歸併的方法將一個個的子序列合併成排序好的序列。分割和歸併的過程可以看下面的圖例。
3.算法主要思想
template<class T>
void merge( T r[],T r2[],int s,int mid,int t)
//s爲第一個子表首元素的下標,mid爲第一個子表末元素的下標
//t爲第二個子表末元素的下標
{ int i,j,k;
i=s;j=mid+1;k=s; //k是r2的初始指針
while((i<=mid)&&(j<=t))
{ k=k+1;
if(r[i].key<=r[j].key){r2[k]=r[i];i++;}
else{r2[k]=r[j];j++;}
}
while(i<=mid){k++;r2[k]=r[i];i++;}
while(j<=t){k++;r2[k]=r[j];j++;}
} //merge
4. 算法的Java實現
Java實現的二路歸併排序的算法如下:
public class myMergeSort { static int number=0; public static void main(String[] args) { int[] a = {26, 5, 98, 108, 28, 99, 100, 56, 34, 1 }; printArray("排序前:",a); MergeSort(a); printArray("排序後:",a); } private static void printArray(String pre,int[] a) { System.out.print(pre+"\n"); for(int i=0;i<a.length;i++) System.out.print(a[i]+"\t"); System.out.println(); } private static void MergeSort(int[] a) { // TODO Auto-generated method stub System.out.println("開始排序"); Sort(a, 0, a.length - 1); } private static void Sort(int[] a, int left, int right) { if(left>=right) return; int mid = (left + right) / 2; //二路歸併排序裏面有兩個Sort,多路歸併排序裏面寫多個Sort就可以了 Sort(a, left, mid); Sort(a, mid + 1, right); merge(a, left, mid, right); } private static void merge(int[] a, int left, int mid, int right) { int[] tmp = new int[a.length]; int r1 = mid + 1; int tIndex = left; int cIndex=left; // 逐個歸併 while(left <=mid && r1 <= right) { if (a[left] <= a[r1]) tmp[tIndex++] = a[left++]; else tmp[tIndex++] = a[r1++]; } // 將左邊剩餘的歸併 while (left <=mid) { tmp[tIndex++] = a[left++]; } // 將右邊剩餘的歸併 while ( r1 <= right ) { tmp[tIndex++] = a[r1++]; } System.out.println("第"+(++number)+"趟排序:\t"); // TODO Auto-generated method stub //從臨時數組拷貝到原數組 while(cIndex<=right){ a[cIndex]=tmp[cIndex]; //輸出中間歸併排序結果 System.out.print(a[cIndex]+"\t"); cIndex++; } System.out.println(); } }
排序前: 26 5 98 108 28 99 100 56 34 1 開始排序 第1趟排序: 5 26 第2趟排序: 5 26 98 第3趟排序: 28 108 第4趟排序: 5 26 28 98 108 第5趟排序: 99 100 第6趟排序: 56 99 100 第7趟排序: 1 34 第8趟排序: 1 34 56 99 100 第9趟排序: 1 5 26 28 34 56 98 99 100 108 排序後: 1 5 26 28 34 56 98 99 100 108