[算法入门]--十分钟弄懂归并排序

目录

一、问题(合并子功能的实现):

二、递归思路

三、全流程完整代码(递归函数+合并函数)

四、代码效果

五、总结与学习建议


一、问题(合并子功能的实现):

想要弄懂归并排序,首先要弄懂这样一个问题:

        1.给定两个有序数组,如何将这两个数组合并到一个数组中去,同时还要保证这个新的数组是有序的呢?(图片来自别的博主)

c598f55dfb804711b3dc0fed5f2dc84b.png


        2.根据这个过程,我们可以设计一个代码来进行合并的操作,具体思路如下:

1、使用双指针分别指向两个数组的开始

2、开辟一个新的辅助数组空间

3、将指针数值小的元素拷贝到辅助空间,该指针后移

4、必然会出现两种情况,即其中一个指针会先越界

5、判断指针的越界情况,将未越界的剩余元素全部移到辅助空间


我们可以发现,能这样做的首要前提是两个待处理数组都是有序的。

我们每次都将最小的数字移入空间,那么最后剩下的一批肯定比已经移入的元素要大,可以自行画图移动来进行理解。


        3.好,那我们现在来设计对应的代码来实现合并的操作:

void merge(vector<int>& arr, int L, int M, int R) {
int i = L, j = M + 1;
vector<int> tem; //定义临时数组存放排序好的数据
while (i <= M && j <= R) {
if (arr[i] <= arr[j]) tem.push_back(arr[i++]); //先拷贝再自增 简化代码
else tem.push_back(arr[j++]);
}
while (i <= M) tem.push_back(arr[i++]); //如果是j越界了,i还么放完,剩下的全塞进去
//这两个while只会中其中一个
while (j <= R) tem.push_back(arr[j++]);
int t = 0, p = L; //t指向tem,p指向原数组
while (p <= R) arr[p++] = tem[t++]; //覆盖元素组[L,R]区间上的元素
}

 在这个函数中,我们的L,M,R规定了这两个和并数组的界限:
[L,M]是第一个数组的下标范围,[M+1,R]是第二个数组的下标范围


二、递归思路

递归设计我们每次将数组同过传入递归传入的参数范围,将数组平分。

返回条件当(L+R)传入的参数左右范围是同一个值说明此时已经不能再往下拆分,停止递归。

回溯调用合并函数,将每次将下一层递归处理好的子数组进行合并(merge操作)。


三、全流程完整代码(递归函数+合并函数)

#include <vector> //用于动态数组
#include <iostream>
#include <ctime> //用于生成随机数种子
#include <cstdlib> //用于rand()
using namespace std;
int randint(int a, int b) {
return rand() % (b - a + 1) + a;
}
void initArr(vector<int>& arr, int N) {
for (int i = 0; i < N; i++) arr.push_back(randint(1, 100));
//生成数值1到100范围的长度为N数组
}
void merge(vector<int>& arr, int L, int M, int R) {
int i = L, j = M + 1;
vector<int> tem; //定义临时数组存放排序好的数据
while (i <= M && j <= R) {
if (arr[i] <= arr[j]) tem.push_back(arr[i++]); //先拷贝再自增 简化代码
else tem.push_back(arr[j++]);
}
while (i <= M) tem.push_back(arr[i++]); //如果是j越界了,i还么放完,剩下的全塞进去
//这两个while只会中其中一个
while (j <= R) tem.push_back(arr[j++]);
int t = 0, p = L; //t指向tem,p指向原数组
while (p <= R) arr[p++] = tem[t++]; //覆盖元素组[L,R]区间上的元素
}
void mergeSort(vector<int>& arr, int L, int R) {
if (L == R) return; //L==R说明递归到最底部,这时开始回溯
int mid = L + ((R - L) >> 1); //等同与L + (R - L)/2 但是位运算更帅且更快~
//这里注意+优先级大于>>
//之前我写一直出bug,上网一搜位运算优先级,有个大哥也是在写归并排序出现了这个同样的问题,说来真巧~
// https://blog.csdn.net/hhhenjoy/article/details/115479935参见这篇blog
mergeSort(arr, L, mid); //递归左边
mergeSort(arr, mid + 1, R); //递归右边
//先递归到最底部再回溯然后merge归并起来
merge(arr, L, mid, R);
//归并下一层的有序数组
}
int main() {
srand(time(0)); //生成随机数种子来随机生成数组
vector<int> arr;
initArr(arr, 50); //调用初始化数组函数
vector<int>::iterator it = arr.begin(); //建立一个迭代器
cout << "未排序的数组:" << endl;
for (; it < arr.end(); it++) cout << *it << ' ';cout << endl; //打印没有排序的数组
mergeSort(arr, 0, arr.size() - 1); //归并排序范围为整个数组
cout << "排好序的数组:" << endl;
it = arr.begin(); //初始化迭代器让他回到第一个位置
for (; it < arr.end(); it++) cout << *it << ' ';cout << endl; //打印排好序的数组
}

四、代码效果

3a43af2051af40abb7a31006e701ed47.png


五、总结与学习建议

        1、归并排序,实际上是递归算法的一种实现,巧妙地利用了递归栈存函数,从而延时调用的性质。

        2、在学习归并之前(快排也是一个原理),最好是先弄懂递归调用的底层原理,然后能够独立设计出merge(合并部分)算法,这时再来看归并会通透很多。

posted @   IoOozZzz  阅读(9)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示