文字描述
假设初始序列有n个记录,则可看成是n个有序的字序列,每个字序列的长度为1,然后两两归并,得到[n/2]个长度为2或1的有序子序列;再两两归并,…, 如此重复,直到得到一个长度为n的有序序列为止,这种排序方法称为2-路归并排序。
示意图
算法分析
2-路归并排序的时间复杂度为nlogn;
2-路归并排序需要至少同待排序序列同等大小的辅助空间;
与快速排序和堆排序相比,归并排序最大特点就是,它是一种稳定的排序方法。
在一般情况下,2-路归并排序,尤其是递归形式的,很少在内部排序中使用,一般用于外部排序,因为反复的自身函数的调用,容易引起栈溢出。
代码实现
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <math.h> 4 /* 5 * double log2(double x); 以2为底的对数 6 * double ceil(double x); 取上整 7 * double floor(double x); 取下整 8 * double fabs(double x); 取绝对值 9 */ 10 11 #define DEBUG 12 13 #define EQ(a, b) ((a) == (b)) 14 #define LT(a, b) ((a) < (b)) 15 #define LQ(a, b) ((a) <= (b)) 16 17 //定义顺序表中结点个数的最大值 18 #define MAXSIZE 100 19 //定义无穷大INF的值 20 #define INF 1000000 21 22 //定义结点中的关键字类型为int 23 typedef int KeyType; 24 //定义结点中除关键字外的附件信息为int 25 typedef char InfoType; 26 27 //待排序的结点的结构体 28 typedef struct{ 29 //结点中的关键字 30 KeyType key; 31 //结点中的除关键字外的附加信息 32 InfoType otherinfo; 33 }RedType; 34 35 //顺序表的结构体 36 typedef struct{ 37 //顺序表中待排序的结点 38 RedType r[MAXSIZE+1]; 39 //顺序表中待排序的结点个数 40 int length; 41 }SqList; 42 43 //依次打印顺序表中结点的信息 44 void PrintList(SqList L){ 45 int i = 0; 46 printf("下标值:"); 47 for(i=0; i<=L.length; i++){ 48 printf("[%d] ", i); 49 } 50 printf(" 关键字:"); 51 for(i=0; i<=L.length; i++){ 52 if(EQ(L.r[i].key, INF)){ 53 printf(" %-3c", '-'); 54 }else{ 55 printf(" %-3d", L.r[i].key); 56 } 57 } 58 printf(" 其他值:"); 59 for(i=0; i<=L.length; i++){ 60 printf(" %-3c", L.r[i].otherinfo); 61 } 62 printf(" "); 63 return ; 64 } 65 66 //将有序的SR[i,...,m]和SR[m+1,...,n]归并为有序的TR[i,...,n] 67 void Merge(RedType SR[], RedType TR[], int i, int m, int n) 68 { 69 int j = 0, k =0; 70 //将SR中记录由小到大地归并到TR 71 for(j=m+1, k=i; i<=m && j<=n; ++k){ 72 if(LQ(SR[i].key, SR[j].key)){ 73 TR[k] = SR[i++]; 74 }else{ 75 TR[k] = SR[j++]; 76 } 77 } 78 //将剩余的SR[i,...,m]复制到TR 79 for(; i<=m; i++){ 80 TR[k++] = SR[i]; 81 } 82 //将剩余的SR[j,...,n]复制到TR 83 for(; j<=n; j++){ 84 TR[k++] = SR[j]; 85 } 86 } 87 88 //将SR[s,...,t]归并排序为TR1[s,...,t] 89 void MSort(RedType SR[], RedType TR1[], int s, int t) 90 { 91 if(s == t){ 92 TR1[s] = SR[s]; 93 }else{ 94 //将SR[s,...,t]平分为SR[s,...,m]和SR[m+1,...,t] 95 int m = (s+t)/2; 96 RedType TR2[MAXSIZE+1]; 97 //递归地将SR[s,...,m]归并为有序的TR2[s,...,m] 98 MSort(SR, TR2, s, m); 99 //递归地将SR[m+1,...,t]归并为有序的TR2[m+1,...,t] 100 MSort(SR, TR2, m+1, t); 101 //将TR2[s,...,m]和TR2[m+1,...,t]归并到TR1[s,...,t] 102 Merge(TR2, TR1, s, m, t); 103 } 104 } 105 106 //对顺序表L作2-路归并排序 107 void MergeSort(SqList *L) 108 { 109 MSort(L->r, L->r, 1, L->length); 110 #ifdef DEBUG 111 printf("对该数据作2-路归并排序后: "); 112 PrintList(*L); 113 #endif 114 } 115 116 int main(int argc, char *argv[]) 117 { 118 if(argc < 2){ 119 return -1; 120 } 121 SqList L; 122 int i = 0; 123 for(i=1; i<argc; i++){ 124 if(i>MAXSIZE) 125 break; 126 L.r[i].key = atoi(argv[i]); 127 L.r[i].otherinfo = 'a'+i-1; 128 } 129 L.length = (i-1); 130 L.r[0].key = 0; 131 L.r[0].otherinfo = '0'; 132 printf("输入数据: "); 133 PrintList(L); 134 //对顺序表L最2-路归并排序 135 MergeSort(&L); 136 return 0; 137 }
运行