God Liao On The Way
阿新 • • 發佈:2019-01-09
歸併排序的流程如下
第一步:對數列每次都進行切分,直到不能再切分
每次都對數列進行切分分組,直到每組的元素都只有一個,學過遞迴的話很容易想到這種重複性的動作用遞迴很容易實現。對於8個數的數列,切分三次直到第四層就不能再切分了。
第二步:進行歸併
對於上述的數列,當每組的元素都是一個,也就是說每組的都是有序的了,遞迴返回,返回到倒數第二層。此時可對每組元素進行歸併
再進行歸併
可以看到歸併將每組的數排成有序的了,最後我們將最後兩組數再進行歸併即可。
此時,數列有序,歸併結束
程式設計思路
對於每次把數列按半切分分組,對分好的組進行歸併這個流程可以用遞迴實現:
//歸併過程
public static void merge(int arr[],int l,int mid,int r){
//歸併排序輔助陣列
int T[] = new int[r-l+1];
//T[0]到T[r-l]儲存arr[l]到arr[r]的值
for(int i = l; i <= r; i++){
T[i-l] = arr[i];
}
//使用i指向分組1的第一個數的位置,j指向分組2的第一個數的索引
int i = l,j = mid+1 ;
//需要歸併的陣列位置是[l,r]
for(int k = l ; k <= r; k++){
if(i > mid){ //歸併後,分組2還有元素,依次覆蓋到原陣列對應處
arr[k] = T[j-l];
j++;
}else if(j > r){ //歸併後,分組1還有元素,依次覆蓋到原陣列對應處
arr[k] = T[i-l];
i++;
}else if(T[i-l] < T[j-l]){ //將分組中小的數覆蓋到原陣列對應處
arr[k] = T[i-l];
i++;
}else if(T[i-l] >= T[j-l]){
arr[k] = T[j-l];
j++;
}
}
}
T[]是輔助陣列,用來存放兩個需要進行歸併的分組。在歸併時,每次將兩組中的最小的那個數依次放到原陣列。
這個過程如下所示:
優化
public static void merge_sort(int arr[],int l,int r){
if(l >= r)
return;
/**對於數不是很多的情況下,可以使用插入排序代替歸併來提高效率
* if(r - l <= 10){
* 插入排序;
* return;
* }
*/
int mid = (l+r) / 2;
merge_sort(arr,l,mid);
merge_sort(arr,mid+1,r);
//優化,歸併時左邊的最後一個數已經是小於右邊第一個數時,可以不用歸併了
if(arr[mid] > arr[mid+1]){
merge(arr,l,mid,r);
}
}