内部排序->归并排序->2-路归并排序

文字描述

  假设初始序列有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("\n关键字:");
 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("\n其他值:");
 59     for(i=0; i<=L.length; i++){
 60         printf(" %-3c", L.r[i].otherinfo);
 61     }
 62     printf("\n\n");
 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-路归并排序后:\n");
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("输入数据:\n");
133     PrintList(L);
134     //对顺序表L最2-路归并排序
135     MergeSort(&L);
136     return 0;
137 }
2-路归并排序

 

运行

 

posted on 2018-07-30 18:09  LiveWithACat  阅读(857)  评论(0编辑  收藏  举报