归并排序

对《大话数据结构》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  }

运行结果:

时间复杂度:

posted @ 2016-04-25 14:33  Pearl_zju  阅读(113)  评论(0编辑  收藏  举报