归并排序用的是递归算法,昨天已经基本搞懂了递归算法的原理,今天就来实践一下(代码是看网上的一个老师讲的,我在理解的基础上,自己将代码打了出来)
归并排序的概念
归并 是将两个或者是两个以上的有序表组合成一个新的有序表
两个有序表的合并
假设有L1与L2两个有序表如何将他们合并为一个有序表呢?
首先要借助一个辅助数组temp大小为L,显然L>=L1+L2;
(1)比较L1与L2首个元素,哪个小哪个放入temp中
(2)将放入temp数组的元素的所在的初始数组的第二个数作为他的第一个元素,并且将他的长度减一
重复操作
直到有一个数组的长度为零时,将剩余的数组的所有元素按照顺序添加到temp中
要清楚二路归并是将两个表归并
分为两个表,那么两个长度的绝对值之差小于一最好
接着,我们要将左表进行递归排序,右表也进行递归排序,然后再将他们合并,就解决了递归的问题
但是,递归是有终止条件的!
终止条件是什么呢?
显然,我们知道,一个表不为空的表尾下标至少要大于或等于表头下标,临界情况就是表头和表尾的下标相同(我们所说的不是循环的)。如果说表尾和表头想同了,就只有一个元素!如果再继续的话一个为空,另一个有一个元素,再将这一个元素分下去就无限循环了。所以临界条件出来了如果说开始位置start>=end(末尾下标),那么就要结束。
实现代码
void sort(int a[],int start,int end)
{
int mid;
mid=(start+end)/2;
if(start>=end) return;
sort(a,start,mid);
sort(a,mid+1,end);
merg(a,start,end);
}
接着是merg函数的实现,merg是将两个有序表合并
我们还是用前面的图帮助我们理解

当我们合并红圈上的两个时,我们可以看做是

上图中的分为两个子表的合并
因此我们要申请两个数组来存储这两个子表
然后将他们存进去之后,再进行上面所说的两个子表的合并
代码如下
void merg(int a[],int start,int end)
{
int i,j,k=start,mid;
int *k11,*k22;//将一个数组分成两份,然后将这两个数组合成一个有序的数组
int k1,k2;//k11与k22的长度
mid=(end+start)/2;
k1=mid-start+1;
k2=end-mid;
k11=(int *)malloc(sizeof(int)*k1);
k22=(int *)malloc(sizeof(int)*k2);
for(i=0;i<k1;i++)//将表分成两个部分存放在两个申请的数组里
k11[i]=a[start++];
for(j=0;j<k2;j++)
k22[j]=a[start++];
i=0,j=0;
while(i<k1&&j<k2)
{
if(k11[i]>k22[j])//从小到大排列
{
a[k]=k22[j];
j++;
}
else
{
a[k]=k11[i];
i++;
}
k++;
}
while(i<k1)//说明k11剩余,将剩余的放入到数组a中
a[k++]=k11[i++];
while(j<k2)
a[k++]=k22[j++];
free(k11);//申请的内存释放
free(k22);
}
值得注意的是
k1=mid-start+1;
k2=end-mid;
k1与k2的长度
刚开始我认为他们的长度是
k1=(end-start)/2+1;
k2=(end-start)/2;
这是有点愚蠢的,如果说end-start+1为偶数,那么就不成立了
假设start=2,end=7;
包括了6个数
按照上面的进行计算k1=3,k2=2显然错误
7313

被折叠的 条评论
为什么被折叠?



