归并算法是一种效率较高且稳定的算法,归并算法总是要将序列中的记录都扫描一遍,所以总的时间复杂度为o(nlogn),这是归并算法中最好、最坏、平均的时间性能。
递归方式的归并算法:
首先定义函数 sort(int SR[ ], int s, int t),
void sort(int SR[], int s, int t)
{
int temp;
if(SR[s] > SR[t])
{
temp = SR[t];
SR[t] = SR[s];
SR[s] = temp;
}
return;
}
sort函数的作用是将数组SR[]中下标为s和t的两个元素的位置进行交换。
接下来是比较关键的Merge函数,Merge(int SR[ ], int s, int m, int t)
void Merge(int SR[], int s, int m, int t)
{
int temp[MAXSIZE];
int k;
int i, j;
k = 0;
i = s;
j = m+1;
while(i<=m&&j<=t)
{
if(SR[i] < SR[j])
{
temp[k] = SR[i];
++k;
++i;
}
else
{
temp[k] = SR[j];
++k;
++j;
}
}
if(i>m)
{
while(j<=t)
{
temp[k] = SR[j];
++k;
++j;
}
}
else
{
while(i<=m)
{
temp[k] = SR[i];
++k;
++i;
}
}
for(j = s; j<=t;++j)
SR[j] = temp[j-s];
}
这个函数的作用是这样的,假设SR[s.........m]数组已经是有序数组,SR[m+1..............t]数组也是有序数组,要将他们归并成一个有序数组SR[s..........................t]。
最后的总函数void MSort(int SR[ ], int s, int t)
void MSort(int SR[], int s, int t)
{
if(s==t)
return;
if((s+1)==t)
{
sort(SR,s,t);
return;
}
else
{
int m;
m = (s+t)/2;
MSort(SR, s, m);
MSort(SR, m+1, t);
Merge(SR,s, m, t);
}
}
分析下其空间复杂度,Merge函数中需要另外分配空间temp[MAX],加上递归造成的函数的堆栈深度log(n),所以总的空间复杂度是o(log(n) +n)(大话数据结构)。
采用递归的方法进行递归调用的时候,需要重新开辟栈空间,又要返回,会造成时间和空间上的损耗,下面是非递归调用所采用的代码。
首先是函数MergePass(int array, int s, int n)
void MergePass(int array[], int s, int n)
{
if(n<=s)
return;
if(s<n&&n<=2*s)
Merge(array,1, s, n);
else
{
int i;
i = 1;
while((i+2*s-1)<=n)
{
Merge(array, i, i+s-1, i+2*s-1);
i = i+2*s;
}
if((i+s-1)>=n)
return;
else
{
Merge(array, i, i+s-1, n);
}
}
}
这个函数的作用是这样的,从第一个元素开始,将array中相邻的长度为(元素个数)s的子序列两两归并,array序列具有这样的性质,从第一个元素开始,每个长度为s的序列都是有序的,划分到最后,如果序列长度小于或等于s,这个序列也是有序的,这个函数的作用就是将array序列每s个元素有序变成每2s个元素有序,注意其中序列的几种情况的不同处理。
最后的函数是这样的:
void FinalMerge(int array[], int n)
{
int k;
for(k =1; k<=n;k = k*2)
MergePass(array, k, n);
}
k从1开始两两归并,然后k等于2,再来两两归并,然后k等于4来进行两两归并.....最后整个数列成为有序数列。
此外要特别注意的是各个参数和数组中元素的对应关系(C语言中数组中第一个元素的下标为0)。
非递归的方法不需要消耗因递归调用引起的时间和空间,空间复杂读o(n)(Merge函数中需要的空间),时间复杂度是归并排序的时间复杂度o(nlogn)。
主要参考《大话数据结构》,代码以及函数参数稍有变化,以上代码已经进行测试。