归并排序
对《大话数据结构》P406~P416—归并排序,进行了自己的理解并完善了代码。
一、递归实现归并排序
代码和解释如下(VS2012测试通过):
1 #include <iostream> 2 using namespace std; 3 #define MAXSIZE 9//用于要排序数组个数最大值,可根据需要修改 4 5 //排序用的顺序表结构 6 typedef struct 7 { 8 int r[MAXSIZE+1];//定义一个数组,用于存储要排序的数,r[0]作为临时变量 9 int length;//用于记录顺序表的长度 10 }SqList; 11 12 //排序表的初始化 13 SqList *InitSqList(SqList *L) 14 { 15 L=new SqList; 16 L->length=MAXSIZE;//本例中长度是9 17 cout<<"input list"<<endl; 18 for(int i=1;i<=L->length;i++) 19 cin>>L->r[i]; 20 return L; 21 } 22 23 //数组遍历输出 24 void PrintSqList(SqList *L) 25 { 26 for(int i=1;i<=L->length;i++) 27 cout<<L->r[i]<<" "; 28 cout<<endl; 29 } 30 31 //交换r[i]和r[j] 32 void swap(SqList *L,int i,int j) 33 { 34 int temp=L->r[i]; 35 L->r[i]=L->r[j]; 36 L->r[j]=temp; 37 } 38 39 //数组遍历输出 40 void Print(int *R) 41 { 42 for(int num=1;num<=MAXSIZE;num++) 43 cout<<R[num]<<" "; 44 cout<<endl; 45 } 46 47 //将有序的temp[s..m]和temp[m+1..t]归并为有序的TR[s..t] 48 void Merge(int temp[],int TR[],int s,int m,int n) 49 { 50 int j,k,l; 51 for(j=m+1,k=s;s<=m && j<=n;k++)//将temp中记录由小到大地并入TR 52 { 53 if (temp[s]<temp[j]) 54 TR[k]=temp[s++]; 55 else 56 TR[k]=temp[j++]; 57 } 58 if(s<=m) 59 { 60 for(l=0;l<=m-s;l++) 61 TR[k+l]=temp[s+l];//将剩余的temp[s..m]复制到TR 62 } 63 if(j<=n) 64 { 65 for(l=0;l<=n-j;l++) 66 TR[k+l]=temp[j+l];//将剩余的temp[j..n]复制到TR 67 } 68 } 69 70 //递归法,将SR[s..t]归并排序为TR[s..t] 71 void MSort(int SR[],int TR[],int s, int t) 72 { 73 int m; 74 int temp[MAXSIZE+1];//用来存储归并前的二路,分为temp[s..m]和temp[m+1..t],m=(s+t)/2 75 if(s==t) 76 TR[s]=SR[s];//最极端的情况,也是递归的终止情况,子序列长度为1 77 else 78 { 79 m=(s+t)/2;//将元素的序列SR[s..t]平分为两部分,SR[s..m]和SR[m+1..t] 80 MSort(SR,temp,s,m);//递归,将前半部分SR[s..m]归并为有序的temp[s..m],递归至子序列长度为1 81 cout<<"temp1:";Print(temp); 82 MSort(SR,temp,m+1,t);//递归,将后半部分SR[m+1..t]归并为有序的temp[m+1..t],递归至子序列长度为1 83 cout<<"temp2:";Print(temp); 84 Merge(temp,TR,s,m,t);//将有序的temp[s..m]和有序的temp[m+1..t],归并到TR[s..t] 85 cout<<"temp3:";Print(temp); 86 cout<<"TR:";Print(TR); 87 } 88 } 89 90 //对顺序表L作归并排序 91 void MergeSort(SqList *L) 92 { 93 MSort(L->r,L->r,1,L->length); 94 } 95 96 int main() 97 { 98 SqList *p=NULL; 99 p=InitSqList(p);//初始化 100 MergeSort(p);//排序 101 cout<<"after sort"<<endl; 102 PrintSqList(p);//输出 103 }
运行结果:
举个4个数的例子便于理解递归过程,只需要把#define MAXSIZE 9修改成#define MAXSIZE 4。
归并排序,原理是假设初始序列有n个值,则可以看成是n子序列,既然每个子序列长度是1,那每个子序列都是有序的。然后不断进行两两归并成新的有序子序列,作为下一次归并的其中一路。
需要两部分:
1、把原始序列一分为二,每路都成为一个有序序列。用递归的方法,把每一路都分至只有一个数,即递归终止开始返回。
//递归法,将SR[s..t]归并排序为TR[s..t]
void MSort(int SR[],int TR[],int s, int t)
2、把有序的两路子序列归并成一路。比如3,1,归并成1,3;4,5,1,6归并成1,4,5,6。
//将有序的temp[s..m]和temp[m+1..t]归并为有序的TR[s..t]
void Merge(int temp[],int TR[],int s,int m,int n)
这个函数作用就是把两路分别有序的temp归并到TR。temp的每一路本身已经有序排列。
比如这个例子,序列短,帮助理解,5,1,4,3:
这部分是递归的结果。两路有序序列5和1。
两路有序序列5和1归并成1,5,作为新的有序子序列。
这部分是递归的结果。两路有序序列4和3。
两路有序序列4和3归并成3,4,作为新的有序子序列。并且将剩余的temp[s..m]复制到TR。
两路有序序列1,5和3,4归并成1,3,4,5,作为新的有序子序列。终止,因为所有递归都已返回。
再看个序列长一点的,原理是一样的。
时间复杂度:
二、非递归实现归并排序
代码和解释如下(VS2012测试通过):
1 #include <iostream> 2 using namespace std; 3 #define MAXSIZE 9//用于要排序数组个数最大值,可根据需要修改 4 5 //排序用的顺序表结构 6 typedef struct 7 { 8 int r[MAXSIZE+1];//定义一个数组,用于存储要排序的数,r[0]作为临时变量 9 int length;//用于记录顺序表的长度 10 }SqList; 11 12 //排序表的初始化 13 SqList *InitSqList(SqList *L) 14 { 15 L=new SqList; 16 L->length=MAXSIZE; 17 cout<<"input list"<<endl; 18 for(int i=1;i<=L->length;i++) 19 cin>>L->r[i]; 20 return L; 21 } 22 23 //数组遍历输出 24 void PrintSqList(SqList *L) 25 { 26 for(int i=1;i<=L->length;i++) 27 cout<<L->r[i]<<" "; 28 cout<<endl; 29 } 30 31 //交换r[i]和r[j] 32 void swap(SqList *L,int i,int j) 33 { 34 int temp=L->r[i]; 35 L->r[i]=L->r[j]; 36 L->r[j]=temp; 37 } 38 39 //数组遍历输出 40 void Print(int *R) 41 { 42 for(int num=1;num<=MAXSIZE;num++) 43 cout<<R[num]<<" "; 44 cout<<endl; 45 } 46 47 //将有序的temp[s..m]和temp[m+1..t]归并为有序的TR[s..t] 48 void Merge(int temp[],int TR[],int s,int m,int n) 49 { 50 int j,k,l; 51 for(j=m+1,k=s;s<=m && j<=n;k++)//将temp中记录由小到大地并入TR 52 { 53 if (temp[s]<temp[j]) 54 TR[k]=temp[s++]; 55 else 56 TR[k]=temp[j++]; 57 } 58 if(s<=m) 59 { 60 for(l=0;l<=m-s;l++) 61 TR[k+l]=temp[s+l];//将剩余的temp[s..m]复制到TR 62 } 63 if(j<=n) 64 { 65 for(l=0;l<=n-j;l++) 66 TR[k+l]=temp[j+l];//将剩余的temp[j..n]复制到TR 67 } 68 } 69 70 //非递归法,将SR[]中相邻长度为s的子序列两两归并到TR[] 71 void MergePass(int SR[],int TR[],int s,int n) 72 { 73 int i=1; 74 int j; 75 while(i <= n-2*s+1)//两两归并 76 { 77 Merge(SR,TR,i,i+s-1,i+2*s-1); 78 i=i+2*s; 79 } 80 if(i<n-s+1)//归并最后两个子序列 81 Merge(SR,TR,i,i+s-1,n); 82 else//如果最后只剩下单个子序列 83 for(j =i;j <= n;j++) 84 TR[j] = SR[j]; 85 } 86 87 //对顺序表L作非递归的归并排序 88 void MergeSort2(SqList *L) 89 { 90 int* TR=(int*)malloc(L->length * sizeof(int));//申请额外的数组内存空间,用来存放归并结果 91 //用递归方法,递归时深度为log2n(2是下标),非递归方法,空间只用到临时用的TR数组,因此空间复杂度是O(n) 92 int k=1; 93 while(k<L->length) 94 { 95 MergePass(L->r,TR,k,L->length);//将无序数组r[]两两归并入TR 96 k=2*k;//子序列长度加倍 97 cout<<"TR:";Print(TR); 98 MergePass(TR,L->r,k,L->length);//将TR中已经两两归并的有序序列再次归并回数组r[] 99 k=2*k;//子序列长度加倍 100 cout<<"r:";Print(L->r); 101 } 102 } 103 104 int main() 105 { 106 SqList *p=NULL; 107 p=InitSqList(p);//初始化 108 MergeSort2(p);//排序 109 cout<<"after sort"<<endl; 110 PrintSqList(p);//输出 111 }
运行结果:
时间复杂度: