当前位置: 首页 > news >正文

【数据结构初阶】一文带你学会归并排序(递归非递归)

目录

前言

递归实现

代码实现

 非递归实现

代码实现

总结


 

前言

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

  • 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
  • 自下而上的迭代;

和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是 O(nlogn) 的时间复杂度。代价是需要额外的内存空间。

递归实现

在我们前边的学习过程中,例如合并两个有序数组等问题,我们就使用过归并的思想,本质上来说归并排序还是分治的思想,将大问题化为小问题,然后解决小问题,最终是实现大问题的解决。

 动图演示

 

归并排序的递归实现并不复杂,有以下几个步骤:

1.首先申请一段空间tmp,用来保存以及排好序的部分数据,当所有数据都排序完后,重新拷贝回原数组。

2.对数组数据进行分割,例如二叉树分为左右子树一样,也将数组分割为左右数组,知道左指针left大于等于右指针right时,返回。

3.对以及递归好的数据进行排序,两个区域内的数据进行比较,小的数据插入到tmp数组中,直至到数组的最后一个数据,如果当一个数组提前结束,直接将另外一个数组数据直接拷贝即可。

4.将排序好的tmp数组拷贝回原数组。

代码实现

由于原函数不适合递归,所以我们定义子函数,并且求出left和right进行递归,将数组分为[left,mid]和[mid+1,right]两个部分,切记free我们申请的空间,其余按照思路实现即可。

void _MergeSort(int* a, int left, int right, int* tmp)
{if (left >= right)return;int mid = left + (right - left) / 2;_MergeSort(a, left, mid, tmp);_MergeSort(a, mid + 1, right, tmp);int i = left;int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;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++];}for (int i = left; i <= right; i++){a[i] = tmp[i];}
}
void MergeSort(int* a, int n)
{int left = 0;int right = n - 1;int* tmp = (int*)malloc(sizeof(int)*n);if (tmp == NULL){perror("malloc fail");exit(-1);}_MergeSort(a, left, right, tmp);free(tmp);tmp = NULL;
}

 非递归实现

归并的非递归实现起来比递归实现较难一点,但是还是分治的思想,只不过非递归有点类似于二叉树的后序遍历,我们使用gap来控制每次归并时数组内数据个数,例如第一次就是一个一个数据归并成两个数据的有序数组,第二次使用两个数据的有序数组归并成四个数据的有序数组,所以gap是由1开始,并且每次乘2。

非递归实现就是在gap等于1时,将整个数组元素排序成两个两个有序,这个递归实现是不同的。

但是当我们每次将gap乘2时,我们发现数组元素个数不一定是2的次方倍,所以不进行处理时,我们的数组一定会造成越界访问。

我们对每次要归并的数组,第一个数组起始为begin1,结束为end1,第二个数组起始为begin2,结束为end2,所以就会有以下三种情况越界:

1.end1越界,即end1>=n。

2.begin2越界,即begin2>n。

3.end2越界,即end2>=n。

所以我们要对边界进行修正,当边界>=n时,我们将其赋值为n-1,修正如下:

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

我们注意到当begin1>=n时,我们将begin2 赋值为n,end2赋值为n-1,我们发现这样的话这段区间就不存在了,这是为什么呢,我们来探究一下。

 

 我们对程序进行以上的处理,发现程序崩溃了,通过调试发现是tmp数组越界了,那么tmp数组为什么会越界呢?

 通过测试发现,本来只有十个数据,所以下标最多到9,但是tmp数组的下标10的位置插入元素,导致越界,这是因为当[begin2,end2]原本不存在,但是我们修正让其存在[9,9],多插入一个数据,所以导致越界,所以我们做一下修改。

 处理过后就没有下标的越界了。

代码实现

当我们解决这个问题之后,其余代码按照思路实现就好了。

void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("maolloc fail");exit(-1);}int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2*gap - 1;int InDex = i;if (end1 >= n){end1 = n - 1;}if (begin2 >= n){begin2 = n;end2 = n - 1;}if (end2 >= n){end2 = n - 1;}/*printf("[%d,%d] ", begin1, end1);printf("[%d,%d] ", begin2, end2);*/while (begin1 <= end1 && begin2 <= end2){//printf("%d ", InDex);if (a[begin1] < a[begin2]){tmp[InDex++] = a[begin1++];}else{tmp[InDex++] = a[begin2++];}}while (begin1 <= end1){//printf("%d ", InDex);tmp[InDex++] = a[begin1++];}while (begin2 <= end2){//printf("%d ", InDex);tmp[InDex++] = a[begin2++];}}for (int j = 0; j < n; j++){a[j] = tmp[j];}gap *= 2;}free(tmp);tmp = NULL;
}

总结

我们今天讲解了归并排序的递归和非递归的实现方法,码文不易,希望可以对大家有所帮助。

 

相关文章:

【数据结构初阶】一文带你学会归并排序(递归非递归)

目录 前言 递归实现 代码实现 非递归实现 代码实现 总结 前言 归并排序&#xff08;Merge sort&#xff09;是建立在归并操作上的一种有效的排序算法。该算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一个非常典型的应用。 作为一种典型的分而治之思想…...

Simulink壁咚(一)——What and How

目录 一、前言 二、Simulink 知多少 三、滤波算法 四、Model Verification 五、Model Coverage 六、Simulink测试实例 七、Simulink Test 八、Test Manager 九、Test Harness 十、 学习 一、前言 Simulink从2017b以后更加工程化和实用化&#xff0c;基于MBD的功能日趋…...

【PyTorch】Pytorch基础第0章

本文参加新星计划人工智能(Pytorch)赛道&#xff1a;https://bbs.csdn.net/topics/613989052 这是目录PyTorch的简介PyTorch 构建深度学习模型的步骤搭建pytorch使用环境PyTorch的简介 PyTorch 是一个开源的机器学习框架&#xff0c;由 Facebook 的人工智能研究院&#xff08;…...

Android学习总结

积累熟练掌握 Java 语言&#xff0c;面向对象分析设计能力&#xff0c;反射原理&#xff0c;自定义注解及泛型&#xff0c;多次采用设计模式重构公司项目&#xff1b;熟练掌握 IVM 原理&#xff0c;反射&#xff0c;动态代理以及对 ClassLoader 热修复有比较深的理解&#xff1…...

虚拟机ubuntu安装samba服务

安装samba apt-get install samba 新建一个共享目录 mkdir /home/l/work chmod 777 /home/l/work 配置服务 配置 /etc/samba/smb.confsudo smbpasswd -a l(添加用户名名称) 防火墙关闭 Ubuntu中 我们使用命令查看当前防火墙状态; sudo ufw status inactive状态是防火墙关闭…...

开发板中的内存压力测试,你了解多少?

1. 测试目的内存压力测试的目的是评估开发板中的内存子系统性能和稳定性&#xff0c;以确保它能够满足特定的应用需求。开发板通常用于嵌入式系统、物联网设备、嵌入式智能家居等场景&#xff0c;这些场景对内存的要求通常比较高。其内存压力测试的主要目的有&#xff1a;1.对确…...

MATLAB | 这些花里胡哨的热图怎么画

好早之前写过一个绘制相关系数矩阵的代码&#xff0c;但是会自动求相关系数&#xff0c;而且画出来的热图只能是方形&#xff0c;这里写一款允许nan值出现&#xff0c;任意形状的热图绘制代码&#xff0c;绘制效果如下&#xff1a; 如遇到bug请后台提出&#xff0c;并去gitee下…...

Java开发的一些编码建议

1、无论是类、方法、字段、变量&#xff0c;尽可能的限制他们的作用范围&#xff0c;可以避免出现不必要的错误&#xff1b;同时虚拟机也能有更大的优化空间。 2、错误越早发现越好&#xff0c;编译时发生错误比在运行时发生错误好。而且编译时错误能更好的定位问题所在。 这…...

【YOLOv8/YOLOv7/YOLOv5/YOLOv4/Faster-rcnn系列算法改进NO.59】引入ASPP模块

前言作为当前先进的深度学习目标检测算法YOLOv8&#xff0c;已经集合了大量的trick&#xff0c;但是还是有提高和改进的空间&#xff0c;针对具体应用场景下的检测难点&#xff0c;可以不同的改进方法。此后的系列文章&#xff0c;将重点对YOLOv8的如何改进进行详细的介绍&…...

C++STL set/multiset容器 构造和赋值 大小和交换 插入和删除 查找和统计

文章目录set/multiset容器1 set容器 基本概念2 set容器 构造和赋值3 set容器 大小和交换4 set容器 插入和删除5 set容器 查找和统计set/multiset容器 1 set容器 基本概念 简介&#xff1a; 所有元素都会在插入时会被自动排序&#xff0c;例如&#xff0c;在set容器放入元素1、…...

产品研发项目进度管理软件工具有哪些推荐?整理10款最佳进度管理软件

项目进度管理是确保项目按时完成的关键过程&#xff0c;使用合适的项目进度管理工具能确保帮助项目管理者实时了解和控制项目的进展情况&#xff0c;及时发现和解决问题&#xff0c;减少项目风险&#xff0c;提高项目效率和管理水平。这里将整理出国内外最受欢迎的10款项目进度…...

「ML 实践篇」分类系统:图片数字识别

目的&#xff1a;使用 MNIST 数据集&#xff0c;建立数字图像识别模型&#xff0c;识别任意图像中的数字&#xff1b; 文章目录1. 数据准备&#xff08;MNIST&#xff09;2. 二元分类器&#xff08;SGD&#xff09;3. 性能测试1. 交叉验证2. 混淆矩阵3. 查准率与查全率4. P-R 曲…...

从大专到测开,上海某字母站大厂的面试题,岗位是测开(25K*16)

简单介绍一句&#xff0c;大专出身&#xff0c;三年经验。跳了四次槽&#xff0c;面试了无数次&#xff0c;现在把自己的面试经验整理出来分享给大家&#xff0c;堪称必杀技&#xff01; 1&#xff0c;一切从实际出发&#xff0c;对实际工作进行适当修饰 2&#xff0c;不会的简…...

【面试题】Python软件工程师能力评估试题(一)

文章目录前言应试者需知&#xff08;一&#xff09;Python 语言基础能力评估1、理解问题并完成代码&#xff1a;2、阅读理解代码&#xff0c;并在空白处补充完整代码&#xff1a;3、编写一个装饰器&#xff1a;exposer4、阅读代码并在空白处补充完整代码&#xff1a;5、自行用P…...

Java八股文(Java多线程面试题)

并行和并发的区别&#xff1f;&#xff08;1&#xff09;并行是指两个或者多个事件在同一时刻发生&#xff1b;而并发是指两个或多个事件在同一时间间隔发生&#xff1b;&#xff08;2&#xff09;并行是在不同实体上的多个事件&#xff0c;并发是在同一实体上的多个事件&#…...

小程序当前页面如何分享别的页面内容呢?

需求分析 因为功能的需要分为两点 他需要调转转发&#xff0c;并且有首页转发点击button按钮进行转发邀请好友帮忙助力&#xff0c;如何做到一个页面多种转发 如何区分&#xff0c;是button转发还剩右上角三个点转发呢&#xff1f; 通过onShareAppMessage()这个函数的事件…...

编写Java哪个编译器好

现在能够编写Java代码的工具简直不要太多&#xff0c;各种各样五花八门&#xff0c;但目前效率最高的还是Intellij Idea。但这个工具对于完全零基础的小白来说&#xff0c;第一次用起来是比较复杂的&#xff0c;因为它的功能太多了。这就好比你要学开车&#xff0c;如果上来就给…...

第十六章 Java为什么使用序列化

为何要指定serialVersionUID的值如果不指定显示serialVersionUID的值&#xff0c;jvm在序列化时会自动生成一个serialVersionUID&#xff0c;跟属性一起序列化&#xff0c;再进行持久化或者网络传输&#xff0c;在反序列化时&#xff0c;jvm会根据属性自动生成一个新版的serial…...

28岁小公司程序员,无车无房不敢结婚,要不要转行?

大家好&#xff0c;这里是程序员晚枫&#xff0c;又来分享程序员的职场故事了~ 今天分享的这位朋友叫小青&#xff0c;我认识他2年多了。以前从事的是土木行业&#xff0c;2年前找我咨询转行程序员的学习路线和职业规划后&#xff0c;通过自学加入了一家创业公司&#xff0c;成…...

出道即封神的ChatGPT,现在怎么样了?

从互联网的普及到智能手机&#xff0c;都让广袤的世界触手而及&#xff0c;如今身在浪潮中的我们&#xff0c;已深知其力。前阵子爆火的ChatGPT&#xff0c;不少人保持观望态度。现如今&#xff0c;国内关于ChatGPT的各大社群讨论&#xff0c;似乎沉寂了不少&#xff0c;现在怎…...

【计算机视觉】CNN 可视化算法

文章目录一、CAM算法1.1 概述1.2 CAM算法介绍二、Grad-CAM算法2.1 概述2.2 Guided Backpropagation2.3 Occlusion Sensitivity2.4 Grad-CAM 整体结构和效果2.5 Grad-CAM 实现细节一、CAM算法 1.1 概述 本文介绍 2016 年提出的 CAM (Class Activation Mapping) 算法&#xff0…...

自动抓取服务器巡检、登录、执行命令记录+备份脚本

文章目录 引抓取【巡检日志】语言&时区设置语言设置时区巡检脚本执行效果抓取【登录信息】登录脚本登录脚本低版本的last命令执行效果抓取【history记录】说明配置history授权日志文件显示时间戳持久化到日志未配置history的配置过history的执行脚本执行脚本...

如何用Python求解微分方程组

文章目录odeint简介示例odeint简介 scipy文档中将odeint函数和ode, comples_ode这两个类称为旧API&#xff0c;是scipy早期使用的微分方程求解器&#xff0c;但由于是Fortran实现的&#xff0c;尽管使用起来并不方便&#xff0c;但速度没得说&#xff0c;所以有的时候还挺推荐…...

【微信小程序】-- 自定义组件 - behaviors(三十九)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…...

【微信小程序】-- 自定义组件 - 父子组件之间的通信(三十八)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…...

Java Web 实战 11 - 多线程进阶之常见的锁策略

常见的锁策略常见的锁策略1. 乐观锁 VS 悲观锁2. 普通的互斥锁 VS 读写锁3. 重量级锁 VS 轻量级锁4. 自旋锁 VS 挂起等待锁5. 公平锁 VS 非公平锁6. 可重入锁 vs 不可重入锁7. 常见面试题大家好 , 这篇文章给大家带来的是多线程中常见的锁策略 , 我们会给大家讲解 6 种类别的锁…...

(20)目标检测算法之YOLOv5计算预选框、详解anchor计算

目标检测算法之YOLOv5计算预选框、详解anchor计算 单节段目标检测算法中&#xff1a;预选框的设定直接影响最终的检测精度众所周知&#xff0c;yolov5中采用自适应调整预选框anchor的大小&#xff0c;但万事开头难&#xff0c;配置文件config中的预设还是很重要yolo算法作为on…...

3-1 SpringCloud快速开发入门: Ribbon 是什么

接上一章节Eureka 服务注册中心自我保护机制&#xff0c;这里讲讲Ribbon 是什么 Ribbon 是什么 通常说的负载均衡是指将一个请求均匀地分摊到不同的节点单元上执行&#xff0c;负载均和分为硬件负载均衡和软件负载均衡&#xff1a; **硬件负载均衡&#xff1a;**比如 F5、深信…...

Java【lambda表达式】语法及使用方式介绍

相关文章目录 第一篇&#xff1a; Java【EE初阶】进程相关知识 进程管理 内存管理 文章目录相关文章目录前言一、lambda表达式 是什么&#xff1f;1, lambda表达式 的背景2, 什么是 函数式接口3, lambda表达式 的语法二、lambda表达式 的使用方式1, 无参无返回值2, 有一个参…...

【AcWing】蓝桥杯备赛-深度优先搜索-dfs(2)

目录 写在前面&#xff1a; 题目&#xff1a;94. 递归实现排列型枚举 - AcWing题库 读题&#xff1a; 输入格式&#xff1a; 输出格式&#xff1a; 数据范围&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 解题思路&#xff1a; 代码&#xff1a; AC &…...

网站优化月总结/就业seo好还是sem

一 PON基础知识 1.1 PON技术概念 PON(Passive Optical Network)即无源光网络&#xff0c;一种基于点到多点(P2MP)拓朴的技术。“无源”指ODN(光分配网络)不含有任何电子器件及电子电源&#xff0c;ODN全部由光分路器Splitter等无源器件组成&#xff0c;不需要贵重的有源电子设…...

光明网/网站关键词优化怎么弄

11、String s "xyz"和String s new String("xyz");区别String s new String("xyz");可能创建两个对象也可能创建一个对象。如果常量池中有hello字符串常量的话&#xff0c;则仅仅在堆中创建一个对象。如果常量池中没有hello对象&#xff0c;则…...

贵州省城市建设厅网站/关键词排名推广方法

大家好&#xff0c; 为提升上传图片的用户体验&#xff0c;我们已经把上传图片后再将图片插入文章的流程做了改进。自此&#xff0c;图片上传完毕后&#xff0c;直接点击后面的“插入”按钮&#xff0c;就可以直接把该图片插入编辑器内光标所在的位置了。如图&#xff1a; 另一…...

汕头网站备案/廊坊快速排名优化

D 题意&#xff1a; 就是让你构造一个n个点的数&#xff0c;然后&#xff0c;一个点度为i的权值为va[i]现在问你构造出的树&#xff0c;最大的权值和是多少。 思考&#xff1a; 刚开始看到感觉就是一共2*(n-1)个度&#xff0c;然后直接完全背包跑一遍&#xff0c;但是不对。然…...

境外社交网站上做推广/深圳市seo上词多少钱

获取输入法候选列表Description: In the following article we are going to learn how to solve problem of such type using class definitions. 说明&#xff1a;在下面的文章中&#xff0c;我们将学习如何解决使用类定义这种类型的问题。 Problem statement: 问题陈述&…...

wordpress和avada/广告投放代理商加盟

一&#xff1a;empty()&#xff1b;判断一个变量是否被认为是空的。当一个变量并不存在&#xff0c;或者它的值等同于FALSE&#xff0c;那么它会被认为不存在。如果变量不存在的话&#xff0c;empty()并不会产生警告。 返回值 当var存在&#xff0c;并且是一个非空非零的值时…...