二路歸併 插入歸併 原地歸併

2021-06-28 06:32:30 字數 2438 閱讀 1135

插入歸併

歸併排序的時間複雜度為o(nlgn),空間複雜度為o(n);

但是一般來講,基於從單個記錄開始兩兩歸併的排序並不是特別提倡,一種比較常用的改進就是結合插入排序,即先利用插入排序獲得較長的有序子串行,然後再兩兩歸併(改進後的歸併亦是穩定的,因為插入排序是穩定的)。之所以這樣改進是有原因的:儘管插入排序的最壞情況是o(n^2),看起來大於歸併的最壞情況o(nlgn),但通常情況下,由於插入排序的常數因子使得它在n比較小的情況下能執行的更快一些,因此,歸併時,當子問題足夠小時,採用插入排序是比較合適的。

複雜度分析

下面分析下插入歸併排序最壞情況下的複雜度:假設整個序列長度為n,當子串行長度為k時,採取插入排序策略,這樣一共有n/k個子序列。

子串行完成排序複雜度:最壞情況下,n/k個子序列完成排序的時間複雜度為o(nk)。證明:每個子串行完成插入排序複雜度為o(k^2),一共n/k個子序列,故為o(nk)。

子串行完成合併複雜度:最壞情況下,合併兩個子串行的時間複雜度為o(n),一共有n/k個子序列,兩兩合併,共需要lg(n/k)步的合併,所以這些子串行完成合併的複雜度為o(nlg(n/k))。

所以改進後的插入歸併排序的最壞情況的複雜度為o(nk+nlg(n/k)),這裡k的最大取值不能超過lgn,顯然如果k大於lgn,複雜度就不是與歸併乙個級別了,也就是說假設乙個1000長度的陣列,採用插入策略排序子串行時,子串行的最大長度不能超過10。

/*

二路歸併排序

*/void merge(int* array,int low,int middle,int high)

else

} while(first<=middle)

while(second<=high)

memcpy(array+low,temp,sizeof(int)*(high-low+1));

delete temp;

}void mergesort(int* array,int begin,int end) }

/* 改進的歸併演算法:插入歸併

*  先通過插入排序得到較長的有序串,然後歸併

*  即,當分解的陣列長度小於一定值時,不再分解,改用插入排序*/ 

#define insert_bound 5

void insertsort(int arr, int beg, int end)

arr[j+1] = temp;

}} void insert_mergesort(int arr, int beg, int end, int temp_arr)

else

}

原地歸併下面舉例說明一種原地歸併排序的思想。

我們知道,無論是基於單個記錄的兩兩歸併,還是利用插入排序先得到較長的子串行然後歸併,在演算法合併的過程中,我們都是在合併「兩個相鄰的有序子串行」。

在了解原地歸併的思想之前,先回憶一下一般的歸併演算法,先是將有序子串行分別放入臨時陣列,然後設定兩個指標依次從兩個子串行的開始尋找最小元素放入歸併陣列中;那麼原地歸併的思想亦是如此,就是歸併時要保證指標之前的數字始終是兩個子串行中最小的那些元素。文字敘述多了無用,見示例**,一看就明白。

假設我們現在有兩個有序子串行如圖a,進行原地合併的**示例如圖b開始

如圖b,首先第乙個子串行的值與第二個子串行的第乙個值20比較,如果序列一的值小於20,則指標i向後移,直到找到比20大的值,即指標i移動到30;經過b,我們知道指標i之前的值一定是兩個子串行中最小的塊。

如圖c,先用乙個臨時指標記錄j的位置,然後用第二個子串行的值與序列一i所指的值30比較,如果序列二的值小於30,則j後移,直到找到比30大的值,即j移動到55的下標;

如圖d,經過圖c的過程,我們知道陣列塊[index, j)中的值一定是全部都小於指標i所指的值30,即陣列塊[index, j)中的值全部小於陣列塊[i, index)中的值,為了滿足原地歸併的原則:始終保證指標i之前的元素為兩個序列中最小的那些元素,即i之前為已經歸併好的元素。我們交換這兩塊陣列的記憶體塊,交換後i移動相應的步數,這個「步數」實際就是該步歸併好的數值個數,即陣列塊[index, j)的個數。從而得到圖e如下:

重複上述的過程,如圖f,相當於圖b的過程,直到最後,這就是原地歸併的一種實現思想,具體**如下。

void revere(int* array,int begin,int end)

else

array[i++] = temp;

middle++;

} }

}

當然也可以使用上面的 merge_second 函式,這也是原地歸併有序序列的方法

參考:

歸併排序(二路歸併)

歸併排序是一種遞迴思想的體現,通過多次合併較小的幾個 二路歸併為兩個 有序陣列形成新的有序表。思路 將陣列分為n nn個一元組,兩兩合併得到二元組,以此類推共合併log 2n log 2n log2 n 次後,陣列變得有序。時間複雜度為o n logn o nlogn o nlog n 編譯環境de...

(1 3 5)歸併排序 二路歸併

歸併排序 merge sort 是將兩個 或兩個以上 有序表合併成乙個新的有序表,即把待排序序列分為若干個有序的子串行,再把有序的子串行合併為整體有序序列。歸併排序的具體做法 把原序列不斷地遞迴等分,直至每等份只有乙個元素,此時每等份都是有序的。相鄰等份合併,不斷合併,直至合併完全。二路歸併 歸併排...

排序 歸併排序(二路歸併)

基本思想 將兩個有序表合併成乙個有序表。將下列兩個已排序的順序表合併成乙個已排序表。順序比較兩 者的相應元素,小者移入另一表中,反覆如此,直至其中任一表都移入另 一表為止。二路歸併排序的基本思想是將兩個有序表合併成乙個有序表。給定排序碼46,55,13,42,94,05,17,70,二路歸併排序過程...