归并排序的递归与非递归实现

1.递归实现

void _MergeSort(int* a, int* tmp, int begin, int end)//子函数

1.if (begin >= end)
{
    return;
}//开头要进行两个参数的判断,保持细节好习惯

2.下面来讲归并的具体思想:其实就是将一个数组不断二分细化,直到分为两两一组再分别进行比较并返回给上一级,接着开辟一个新数组用来暂时储存这些排序好的数字,最后用memcpy将临时数组(tmp)中排序好的数组拷贝到原数组。

3.这里是单趟排序的实现:

int mid = (begin + end) / 2;//分为两个小数组

int begin1 = begin, end1 = mid;
int begin2 = mid + 1, end2 = end;//确定遍历的头尾
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
    if (a[begin1] < a[begin2])
    {
        tmp[i++] = a[begin1++];
    }
    else
    {
        tmp[i++] = a[begin2++];
    }
}
while (begin1 <= end1)
{
    tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
    tmp[i++] = a[begin2++];
}//顺序储存到新数组

4.递归实现:

_MergeSort( a, tmp, begin, mid );
_MergeSort( a, tmp, mid+1, end );
//类似于分为左右树,但要注意递归插入的位置

下面着重分析一下为什么不以下面这种方式递归:

假设begin=0,end=6;那么mid=3;再细分,第一个数组中就会得到mid=2,即出现【2,3】这个小区间,但接着算下去你会发现【2.3】无法再分,所以会陷入死循环

_MergeSort( a, tmp, begin, mid-1 );
_MergeSort( a, tmp, mid, end );

5.拷贝到原数组

memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));//注意memcpy前者是要拷贝到的地方(目的地),后者是用来拷贝的源

到此,子函数写完。

———————————————————————————————————————————

递归主函数

void MergeSort(int* a, int n)
{
    int* tmp = (int*)malloc(sizeof(int) * n);
    if (tmp == NULL)
    {
        perror("malloc fail");
        return;
    }
    _MergeSort(a, tmp, 0, n - 1);
    free(tmp);
    tmp = NULL;
}

这里是最后的成品:

2.非递归实现

单趟排序的思路与上文相同。

这里我们用循环来解决问题————引入gap变量,通过gap的递增(每次*2)来完成:

元素为一的子数组两两归并(gap=1)

元素为二的子数组两两归并(gap=2)

元素为四的子数组两两归并(gap=4)

.............

其中随着gap的不断*2,肯定会出现越界问题,以下代码就是解决之法:

if (begin2 >= n)
{
    break;
}
if (end2 >= n)
{
    end2 = n - 1;
}

越界无非是end1,begin2或者end2越界。

end1,begin2越界归为通一类,这二者越界即代表第二个数组没有需要访问的数字,直接break即可。

但若只有end2越界,则需重新确定end2的值,以便运算。

  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值