資料結構之排序(七)——歸併排序
阿新 • • 發佈:2019-01-22
歸併排序(Merging Sort):假設初始序列含有n個記錄,則可以看成是n個有序的子序列,每個子序列的長度為1,然後倆倆歸併,得到[n/2]([x]表示不小於x的最小整數)個長度為2或1的有序子序列;再倆倆歸併,....,如此重複,直至得到一個長度為n的有序序列為止,這種排序方法稱為2路歸併排序。
原理
演算法
遞迴法
程式碼
#include "stdafx.h" using namespace std; #include<iostream> #include"stdafx.h" //用於要排序陣列個數最大值,可根據需要修改 #define MAXSIZE 10 typedef struct { //用於儲存要排序陣列,r[0]用作哨兵或臨時變數 int r[MAXSIZE + 1]; //用於記錄順序表的長度 int length; }SqList; //交換L中陣列r的下標為i和j的值 void swap(SqList *L, int i, int j) { int temp = L->r[i]; L->r[i] = L->r[j]; L->r[j] = temp; } /* 將有序的SR[i..m]和SR[m+1..n]歸併為有序的TR[i..n] */ void Merge(int SR[], int TR[], int i, int m, int n) { int j, k, l; for (j = m + 1, k = i; i <= m && j <= n; k++) /* 將SR中記錄由小到大地併入TR */ { if (SR[i]<SR[j]) TR[k] = SR[i++]; else TR[k] = SR[j++]; } if (i <= m) { for (l = 0; l <= m - i; l++) TR[k + l] = SR[i + l]; /* 將剩餘的SR[i..m]複製到TR */ } if (j <= n) { for (l = 0; l <= n - j; l++) TR[k + l] = SR[j + l]; /* 將剩餘的SR[j..n]複製到TR */ } } /* 遞迴法 */ /* 將SR[s..t]歸併排序為TR1[s..t] */ void MSort(int SR[], int TR1[], int s, int t) { int m; int TR2[MAXSIZE + 1]; if (s == t) TR1[s] = SR[s]; else { m = (s + t) / 2; /* 將SR[s..t]平分為SR[s..m]和SR[m+1..t] */ MSort(SR, TR2, s, m); /* 遞迴地將SR[s..m]歸併為有序的TR2[s..m] */ MSort(SR, TR2, m + 1, t); /* 遞迴地將SR[m+1..t]歸併為有序的TR2[m+1..t] */ Merge(TR2, TR1, s, m, t); /* 將TR2[s..m]和TR2[m+1..t]歸併到TR1[s..t] */ } } /* 對順序表L作歸併排序 */ void MergeSort(SqList *L) { MSort(L->r, L->r, 1, L->length); } #define N 9 int main() { int d[N] = {50,10,90,30,70,40,80,60,20}; SqList L0; for (int i = 0; i <N; i++) { L0.r[i + 1] = d[i]; } L0.length = N; cout<< "排序前:"; for (int j = 1; j <= L0.length; j++) { cout<< L0.r[j]<<" "; } MergeSort(&L0); cout << "\n遞迴歸併排序後:"; for (int j = 1; j <= L0.length; j++) { cout << L0.r[j]<<" "; } cout << endl; return 0; }
執行結果
演算法複雜度
遞迴歸併的時間複雜度為:O(nlogn) 歸併排序是一種比較佔用記憶體,但卻效率高且穩定的演算法。演算法穩定性
穩定非遞迴法
程式碼
#include "stdafx.h" using namespace std; #include<iostream> #include"stdafx.h" //用於要排序陣列個數最大值,可根據需要修改 #define MAXSIZE 10 typedef struct { //用於儲存要排序陣列,r[0]用作哨兵或臨時變數 int r[MAXSIZE + 1]; //用於記錄順序表的長度 int length; }SqList; //交換L中陣列r的下標為i和j的值 void swap(SqList *L, int i, int j) { int temp = L->r[i]; L->r[i] = L->r[j]; L->r[j] = temp; } /* 將有序的SR[i..m]和SR[m+1..n]歸併為有序的TR[i..n] */ void Merge(int SR[], int TR[], int i, int m, int n) { int j, k, l; for (j = m + 1, k = i; i <= m && j <= n; k++) /* 將SR中記錄由小到大地併入TR */ { if (SR[i]<SR[j]) TR[k] = SR[i++]; else TR[k] = SR[j++]; } if (i <= m) { for (l = 0; l <= m - i; l++) TR[k + l] = SR[i + l]; /* 將剩餘的SR[i..m]複製到TR */ } if (j <= n) { for (l = 0; l <= n - j; l++) TR[k + l] = SR[j + l]; /* 將剩餘的SR[j..n]複製到TR */ } } /* 非遞迴法 */ /* 將SR[]中相鄰長度為s的子序列兩兩歸併到TR[] */ void MergePass(int SR[], int TR[], int s, int n) { int i = 1; int j; while (i <= n - 2 * s + 1) {/* 兩兩歸併 */ Merge(SR, TR, i, i + s - 1, i + 2 * s - 1); i = i + 2 * s; } if (i<n - s + 1) /* 歸併最後兩個序列 */ Merge(SR, TR, i, i + s - 1, n); else /* 若最後只剩下單個子序列 */ for (j = i; j <= n; j++) TR[j] = SR[j]; } /* 對順序表L作歸併非遞迴排序 */ void MergeSort(SqList *L) { int* TR = (int*)malloc(L->length * sizeof(int));/* 申請額外空間 */ int k = 1; while (k<L->length) { MergePass(L->r, TR, k, L->length); k = 2 * k;/* 子序列長度加倍 */ MergePass(TR, L->r, k, L->length); k = 2 * k;/* 子序列長度加倍 */ } } #define N 9 int main() { int d[N] = {50,10,90,30,70,40,80,60,20}; SqList L0; for (int i = 0; i <N; i++) { L0.r[i + 1] = d[i]; } L0.length = N; cout<< "排序前:"; for (int j = 1; j <= L0.length; j++) { cout<< L0.r[j]<<" "; } MergeSort(&L0); cout << "\n非遞迴歸併排序後:"; for (int j = 1; j <= L0.length; j++) { cout << L0.r[j]<<" "; } cout << endl; return 0; }