在算法导论中,归并算法划归到分治策略中讲述。基本思想就是将大的问题分成小的问题,然后分而治之。实现该算法,既可以采用递归函数;也可以由底向上,通过修改跨度来实现归并。下面就分别贴出这两种算法的简单实现。由于并没有对算法进行大规模的数据测试,所以错误之处望大家斧正。
不管是递归还是直接归并,均需用到下述函数:函数的作用是将p到q位置以及q+1到r位置已经排好序的子数组合并为一个整体数组。
void MERGE(int A[],int p,int q,int r)
{
int i,j,k;
int L[100],R[100];
int n1=q-p+1;//前一个子数组中数字的个数
int n2=r-q;//后一个子数组中数字的个数
for(i=0;i<n1;i++)
L[i]=A[p+i];
L[i]=INT_MAX;//实现哨兵作用
for(i=0;i<n2;i++)
R[i]=A[q+1+i];
R[i]=INT_MAX;
i=j=0;
for(k=p;k<=r;k++)
A[k]=(L[i]<R[j]?L[i++]:R[j++]);
}
首先是递归策略:
void Merge_Sort_DG(int A[],int start,int end)
{
if(start < end)
{
int mid = (start + end)/2;//实现数据的平等划分
Merge_Sort_DG(A,start,mid);//递归调用,排序左侧
Merge_Sort_DG(A,mid+1,end);//递归调用,排序右侧
MERGE(A,start,mid,end);//将已经排序好的数组合并起来
}
}
非递归策略:d为距离
d=1时:0 1,2 3, 4 5,6 7,.....两个两个数据实现排序合并
d=2时:0 1 2 3,4 5 6 7,........四个四个数据实现合并
d=4时:0 1 2 3 4 5 6 7,........
按照这个思想将数据排序
void Merge_Sort_KD(int A[],int start,int end)
{
int d=1;//d为每次跨越的距离
int length=end-start+1;//标识数组A中待排序的数字的个数
int i;
while(d<length)//此处的条件需要好好思考一下。由于合并的时候,每次将相邻的2d个数据合并到一起。假如//2d>=length,那么说明 “间距”=d 时,一定能将所有的数据排序完毕。而此处用d<length作为判断条件的原因是因为
//在while循环的最后一条语句 d*=2已经将d变为原来的两倍。
{
i=0;
while(i<end)
{
if(i+2*d-1<=end)
MERGE(A,i,i+d-1,i+2*d-1);
else if(i+d-1<=end)
MERGE(A,i,i+d-1,end);
i+=2*d;//每次合并2d个元素,故i跨越距离为2d
}
d*=2;
}
}