二路归并排序


归并排序用的是递归算法,昨天已经基本搞懂了递归算法的原理,今天就来实践一下(代码是看网上的一个老师讲的,我在理解的基础上,自己将代码打了出来)
归并排序的概念
归并 是将两个或者是两个以上的有序表组合成一个新的有序表
两个有序表的合并
假设有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显然错误

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值