归并排序算法(经典返回临时变量版)——C++

归并排序算法思想主要是将两个有序数组合并成为一个有序数组,其关键点采用“分治思想”,“分”是二分法,将无序数组分割成为一个个有序数组,然后通过“治”  将两个有序数组合并成为一个有序数组。时间时间复杂度为为O(nlogn),空间复杂度是O(n)的常量级临时变量,是稳定排序算法。

归并排序主要实现思想:

采用“分治思想”,先“分”将整个无序数组先左边递归,再右边递归,类似二叉树先序遍历方法,将数组分为一个个有序数组;然后通过“治”将一个个有序数组通过合并merge方法组合成一个有序数组;

1.“分”vector<int> merge(vector<int>& nums, int start, int end);从起始和终止位置开始进行二分法。

vector<int> Sorts::merge(vector<int>& nums, int start, int end)
{
    if (start == end) //递归终止条件:如果起始下标等于结束下标,则终止递归
        return { nums[start] }; // 返回左边第一个元素
    int middle = (start + end) / 2; // 分治法,采用二分法,取中间下标开始左右递归,直到一个元素开始返回
    auto left = merge(nums, start, middle); // 先递归左边部分,退出该层后向右递归,直到一个元素
    print(left);
    auto right = merge(nums, middle + 1, end); // 先左边再右边递归取有序数组
    return merge(left, right); // 合并两个有序数组,然后继续回退到上一层左边或者右边递归,直到整个递归结束返回为止
}

一直遍历左边部分数据,然后再返回上层遍历右边数据,这样每次左右部分个子得到一个个或组合后的有序数据组。

即下图1所示,每次都打印遍历后左边的值,可以分析出,这个递归类似二叉树里面的先序遍历,每次总是先遍历左边元素回退上一层后再遍历右边最里层元素,图2打印数据更加印证这先遍历左边再遍历右边顺序。

图1  归并排序遍历后打印左边值

图2  归并排序遍历后打印右边值

 2.步骤1将无须数组分为一个个或一块块有序数组,这时需要将两个有序数组依次合并成一个有序数组vector<int> merge(vector<int>& nums1, vector<int>& nums2);

合并的关键是用两个游走下标分别遍历两个数组,将其中一个较小元素放入新创建的数组里;当其中一个数组遍历完毕后,将剩余数组放入新数组后面则完成排序;如下代码所示:

vector<int> Sorts::merge(vector<int>& nums1, vector<int>& nums2)
{
    int i1{ 0 }, i2{ 0 };
    vector<int> mergeArr(nums1.size() + nums2.size(), 0);
    while (i1 < nums1.size() && i2 < nums2.size()) // 分别用两个下标遍历两个数组,取较小元素放到新数组,直到其中一个数组遍历完毕为止
    {
        //mergeArr[i1 + i2] = nums1[i1] <= nums2[i2] ? nums1[i1++] : nums2[i2++]; 这行在linux下可以,在msvc编译器段错误
        if (nums1[i1] <= nums2[i2]) // 取较小元素放入新数组
        {
            mergeArr[i1 + i2] = nums1[i1]; // 
            ++i1; // msvc ++ 好像跟gcc编译器的实现不一样,这里放在数组里面++会段错误
        }
        else
        {
            mergeArr[i1 + i2] = nums2[i2];
            ++i2;
        }
    }
    while (i1 < nums1.size()) // 将剩余数组放入新数组后面
    {
        mergeArr[i1 + i2] = nums1[i1];
        ++i1;
    }
    while (i2 < nums2.size()) // 将剩余数组放入新数组后面
    {
        mergeArr[i1 + i2] = nums2[i2];
        ++i2;
    }
    return mergeArr;
}

3.下面是完整的示例代码:

Sorts.h

#pragma once

#include <iostream>
#include <vector>

using namespace std;

struct Sorts {    
    void merge(vector<int>& nums);
    
    void print(vector<int>& nums);

private:    
    vector<int> merge(vector<int>& nums, int start, int end);
    vector<int> merge(vector<int>& nums1, vector<int>& nums2);
};

Sorts.cpp

#include "Sorts.h"

void Sorts::merge(vector<int>& nums)
{
    if (nums.size() <= 1)
    {
        return;
    }
    auto tmpNums = merge(nums, 0, nums.size() - 1);
    nums = tmpNums;
}

void Sorts::print(vector<int>& nums)
{
    for (const auto& it : nums)
        cout << it << ",";
    cout << endl;
}

vector<int> Sorts::merge(vector<int>& nums, int start, int end)
{
    if (start == end) //递归终止条件:如果起始下标等于结束下标,则终止递归
        return { nums[start] }; // 返回左边第一个元素
    int middle = (start + end) / 2; // 分治法,采用二分法,取中间下标开始左右递归,直到一个元素开始返回
    auto left = merge(nums, start, middle); // 先递归左边部分,退出该层后向右递归,直到一个元素
    auto right = merge(nums, middle + 1, end); // 先左边再右边递归取有序数组    
    return merge(left, right); // 合并两个有序数组,然后继续回退到上一层左边或者右边递归,直到整个递归结束返回为止
}

vector<int> Sorts::merge(vector<int>& nums1, vector<int>& nums2)
{
    int i1{ 0 }, i2{ 0 };
    vector<int> mergeArr(nums1.size() + nums2.size(), 0);
    while (i1 < nums1.size() && i2 < nums2.size()) // 分别用两个下标遍历两个数组,取较小元素放到新数组,直到其中一个数组遍历完毕为止
    {
        //mergeArr[i1 + i2] = nums1[i1] <= nums2[i2] ? nums1[i1++] : nums2[i2++]; 这行在linux下可以,在msvc编译器段错误
        if (nums1[i1] <= nums2[i2]) // 取较小元素放入新数组
        {
            mergeArr[i1 + i2] = nums1[i1]; // 
            ++i1; // msvc ++ 好像跟gcc编译器的实现不一样,这里放在数组里面++会段错误
        }
        else
        {
            mergeArr[i1 + i2] = nums2[i2];
            ++i2;
        }
    }
    while (i1 < nums1.size()) // 将剩余数组放入新数组后面
    {
        mergeArr[i1 + i2] = nums1[i1];
        ++i1;
    }
    while (i2 < nums2.size()) // 将剩余数组放入新数组后面
    {
        mergeArr[i1 + i2] = nums2[i2];
        ++i2;
    }
    return mergeArr;
}

main.cpp

 #include <vector>
#include "Sorts.h"

using namespace std;

int main()
{
    vector<int> nums = { 2,0,1,6,8,10,5,99,87,333,2,0,1 };
    Sorts sorts;
    sorts.print(nums);
    sorts.merge(nums);
    sorts.print(nums);
   
	return 1;
}

输出结果:

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三公子Tjq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值