归并排序(针对数组) C++代码递归实现

一、思路

我把归并排序大致分成两个部分:排序合并

归并排序重要的思想就是“分治”,所谓“分治”就是把一个大问题化解成多个小问题解决。

比如要对一个数组进行归并排序,那么就可以把他从中间切断,变成两个数组。这两个数组分别排序,对这两个数组分别排序的时候,又可以继续划分。重复这个操作,直到不能再划分。
不能再划分时,就进行排序。不能再划分时,数组一定被分成了最小单元,就是只有一个元素。
在这里插入图片描述
单个元素就可以看成是一个有序数组,那么接下来的操作就是对有序数组进行合并。

排序合并

也就是将两个有序的数组进行组合排序。
首先,归并排序不是一个原地排序算法,他需要额外的空间存储排序好的数组。

开始我以为在数组中不能原地,链表中总可以吧?结果,在做有序链表的合并时,我企图原地完成,但出现一个问题就是:改变next指针后,当前加入有序链表的值并不是剩下未加入的最大的。也就是说,后面的节点进行比较后,如果他的值小于当前节点的值,就需要插入到该节点的前面,而对于单链表来说,想要插入值,必须知道前一个节点的位置。
来个链接感受一下

剑指 Offer 25. 合并两个排序的链表 - 力扣(LeetCode)

言归正传:
只要将两个数组的值依次比较,较小的哪个放入临时数组,最后再将临时数组赋值给原始数组对应的位置

边界值条件

两个数组不一定长度一样,再比较过程中,如果一个数组结束了就跳出循环,将另一个数组剩下的部分赋值给临时数组。
由于我的代码整体上最终返回在原数组上操作后的结果,所以下标的判断很重要,一定要注意自己现在处理的是哪一部份数组,这样才不会出错。

二、代码

#include <bits/stdc++.h>
using namespace std;
// 合并函数:比较左右两边数组元素的大小进行排序重组
void merge(int a[], int left, int right, int addM)
{
    int i = left;
    int j = addM;
    // 设置临时数组的长度
    int num = right - left + 1;
    // 设置临时数据,排序当前区域
    int temp[num] = {0};
    int k = 0;
    // 注意边界条件,这里的addM是原来的middle+1 所以属于右边的数组,左边的数组不能取到
    // 这里的right是原数组的最后一个下边,右边数组需要取到,所以+1。也可以替代成:j <= right
    // 当左边数组结束或者右边数组结束就退出循环
    while (i < addM && j < right + 1)
    {
        // 左边数组的项大于右边数组的项,就将小的那一项(右数组的项)放入临时数组,并且右边数组下标自增到下一个
        if (a[i] > a[j])
        {
            temp[k++] = a[j];
            j++;
        }
        else
        {
            // 否则将左数组的当前项放入临时数组,同时左数组下标自增到下一个元素
            temp[k++] = a[i];
            i++;
        }
    }
    // 如果左边数组结束,就遍历右边数组,把剩下的都放入临时数组
    if (i >= addM)
    {
        for (; k < num; k++)
        {
            temp[k] = a[j++];
        }
    }
    else
    {
        // 否则遍历左边数组,把剩下的都放入临时数组
        for (; k < num; k++)
        {
            temp[k] = a[i++];
        }
    }
    // 把临时数组赋值给原数组,注意原数组的下标,要对应现在正在处理的区间,所以开始下标是left
    for (int i = 0; i < num; i++)
    {
        a[left] = temp[i];
        left++;
    }
}
// 归并排序递归算法,把数组分成多个左右两部分进行处理
// 分到最小单位时才开始排序
void mergeSort(int a[], int left, int right)
{
    // 如果数组只有一个元素,就不用排序
    if (left == right)
    {
        return;
    }
    else
    {
        // 先排序左边的数组
        int middle = (left + right) / 2;
        mergeSort(a, left, middle);
        // 在排序右边的
        mergeSort(a, middle + 1, right);
        // 左右都排序后合并
        merge(a, left, right, middle + 1);
    }
}

// 主函数
int main()
{
    int a[10] = {9, 5, 0, 200, 199, 5, 4, 7, 6, 3};
    mergeSort(a, 0, 9);
    for (int i = 0; i < 10; i++)
    {
        cout << a[i] << " ";
    }
    system("pause");
    return 0;
}

有问题请留言交流。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值