將兩個按值有序序列合併成乙個按值有序序列,則稱之為二路歸併排序,下面有自底向上和自頂向下的兩種排序演算法,自頂向下的排序在本文末講述,使用遞迴實現,**較簡潔,經供參考。
1. 歸併子演算法:把位置相鄰的兩個按值有序序列合併成乙個按值有序序列。例如把序列 x[s..u] = 和 序列 x[u+1..v] = 合併成序列
z[s..v] = , 注意合併前的元素都位於同乙個有序序列的相鄰位置,合併後的有序序列的下標與合併前的序列總的起始下標相同。
演算法過程中需要三個整型變數,i 用來遍歷歸併的前乙個有序序列,其初始位置是s;j 用來遍歷歸併的後乙個有序序列,其初始值是u+1;q 用來指出歸併後得到的有序序列的末尾元素的位置,其初始值是s。當遍歷完成其中的乙個有序序列之後,只需把另乙個未結束有序序列的剩餘元素複製到合併後的有序序列的末尾。
看**:
[cpp]view plain
copy
//將有序的x[s..u]和x[u+1..v]歸併為有序的z[s..v]
void merge(int x, int z, int s, int u, int v)
while( i <= u ) //將x中剩餘元素x[i..u]複製到z
z[q++] = x[i++];
while( j <= v ) //將x中剩餘元素x[j..v]複製到z
z[q++] = x[j++];
} 2. 一趟歸併掃瞄子演算法:將參加排序的序列分成若干個長度為 t 的,且各自按值有序的子串行,然後多次呼叫歸併子演算法merge將所有兩兩相鄰成對的子串行合併成若干個長度為
2t 的,且各自按值有序的子串行。
若某一趟歸併掃瞄到最後,剩下的元素個數不足兩個子串行的長度時:
看**:
[cpp]view plain
copy
/* x[0..n-1]表示參加排序的初始序列
* t為某一趟歸併時子串行的長度
* 整型變數i指出當前歸併的兩個子串行中第1個子序列的第1個元素的位置
* y[0..n-1]表示這一趟歸併後的結果
*/
void mergepass(int x, int y, int n, int t)
if( n - i > t ) //若最後剩下的元素個數大於乙個子串行的長度t時
merge(x, y, i, i + t - 1, n - 1);
else //n-i <= t時,相當於只是把x[i..n-1]序列中的資料賦值給y[i..n-1]
for( j = i ; j < n ; ++j )
y[j] = x[j];
} 3. 二路歸併排序演算法:將參加排序的初始序列分成長度為1的子串行使用mergepass函式進行第一趟排序,得到 n / 2 個長度為 2 的各自有序的子串行(若n為奇數,還會存在乙個最後元素的子串行),再一次呼叫mergepass函式進行第二趟排序,得到 n / 4 個長度為 4 的各自有序的子串行, 第 i 趟排序就是兩兩歸併長度為 2^(i-1) 的子串行得到 n / (2^i) 長度為 2^i 的子串行,直到最後只剩乙個長度為n的子串行。由此看出,一共需要 log2n 趟排序,每一趟排序的時間複雜度是 o(n), 由此可知
該演算法的總的時間複雜度是是 o(n log2n),但是該演算法需要 o(n) 的輔助空間,空間複雜度很大,是 o(n).
看**:
[cpp]view plain
copy
void mergesort(int x, int n)
free(y);
} 程式總的**彙總:
[cpp]view plain
copy
#include
#include
//將有序的x[s..u]和x[u+1..v]歸併為有序的z[s..v]
void merge(int x, int z, int s, int u, int v)
while( i <= u ) //將x中剩餘元素x[i..u]複製到z
z[q++] = x[i++];
while( j <= v ) //將x中剩餘元素x[j..v]複製到z
z[q++] = x[j++];
} /* x[0..n-1]表示參加排序的初始序列
* t為某一趟歸併時子串行的長度
* 整型變數i指出當前歸併的兩個子串行中第1個子序列的第1個元素的位置
* y[0..n-1]表示這一趟歸併後的結果
*/
void mergepass(int x, int y, int n, int t)
if( n - i > t ) //若最後剩下的元素個數大於乙個子串行的長度t時
merge(x, y, i, i + t - 1, n - 1);
else //n-i <= t時,相當於只是把x[i..n-1]序列中的資料賦值給y[i..n-1]
for( j = i ; j < n ; ++j )
y[j] = x[j];
} void mergesort(int x, int n)
free(y);
} void print_array(int array, int n)
int main()
; int size = sizeof(array) / sizeof(int);
mergesort(array, size);
print_array(array, size);
return 0;
} 歸併排序自頂向下排序,僅供參考:
[cpp]view plain
copy
void merge2(int *data, int start, int mid, int end)
while(i <= mid)
temp[k++] = data[i++];
while(j <= end)
temp[k++] = data[j++];
k = 0;
for(i = start; i <= end; ++i)
data[i] = temp[k++];
free(temp);
} //從頂往下
void mergesort2(int *data, int start, int end, int *des)
**:
二路歸併排序演算法
將兩個按值有序序列合併成乙個按值有序序列,則稱之為二路歸併排序,下面有自底向上和自頂向下的兩種排序演算法,自頂向下的排序在本文末講述,使用遞迴實現,較簡潔,經供參考。1.歸併子演算法 把位置相鄰的兩個按值有序序列合併成乙個按值有序序列。例如把序列 x s.u 和 序列 x u 1.v 合併成序列 z...
歸併排序(二路歸併)
歸併排序是一種遞迴思想的體現,通過多次合併較小的幾個 二路歸併為兩個 有序陣列形成新的有序表。思路 將陣列分為n nn個一元組,兩兩合併得到二元組,以此類推共合併log 2n log 2n log2 n 次後,陣列變得有序。時間複雜度為o n logn o nlogn o nlog n 編譯環境de...
二路歸併排序
不是困難的演算法,不過也是練習了下遞迴。include include include using namespace std const int maxn 100 5 int a maxn int b maxn void mergesort int a,int b,int begin,int en...