【数据结构】归并排序 的递归实现与非递归实现

归并排序

  • 前言
  • 一、归并排序递归实现
    • (1)归并排序的核心思路
    • (2)归并排序实现的核心步骤
    • (3)归并排序码源详解
    • (4)归并排序效率分析
      • 1)时间复杂度 O(N*logN)
      • 2)空间复杂度 O(N)
      • 稳定性:稳定
  • 二、归并排序的非递归实现
    • (1) 关于递归的缺点的讨论
  • (2) 归并排序 非递归算法实现思路
  • (3)码源详解
  • (4)运行结果



前言

快速排序:前序
归并排序:后序



一、归并排序递归实现

(1)归并排序的核心思路

将 已有序的子序列 合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。


(2)归并排序实现的核心步骤

在这里插入图片描述

  1. 向下递归 对半分割
  2. 递归返回条件:递归到最小,1个即是有序 [ 控制的是范围 归并的区间 ]
  3. 递归到最深处,最小时,就递归回去,开始分按对半分割分出的范围, 将 已有序的子序列 合并,在 tmp 里进行归并。
  4. 将tmp里形成的有序序列,拷贝回原数组 【 因为下一次递归回去上一层再进行下一次的归并过程中,会将数据在tmp中进行归并,会将tmp中的数据覆盖,所以要及时将小部分已归并排好序的子序列拷贝回原数组 】
  5. 再进行递归返回上一层的递归归并,直到递归层数都结束。


(3)归并排序码源详解

void _MergeSort(DataType* a, DataType* tmp, int begin, int end) {if (begin>=end) {      //递归返回的条件:不正常的的范围 或 只剩1个数return;}int mid = (begin + end) / 2;//先递归到最小//[begin,mid][mid+1,end]_MergeSort(a, tmp, begin, mid);    //数组是从0开始,所以end=mid-1这样设计_MergeSort(a, tmp, mid+1, end);//再进行归并 —— 所以归并的过程,设计在递归后面(后序)//归并到tmp数组,再拷贝回去int begin1 = begin; int end1 = mid;int begin2 = mid + 1; int end2 = end;int index = begin;       //指向tmp,=begin是 根据要进行比较插入的数组的位置 找到其对应在tmp中所对应的位置,则不会覆盖前面已经排好序的数据//原型:合并两组数,且有序while (begin1 <= end1 && begin2 <= end2) {      //&&其中一组满足了条件就不再继续,就跳出循环if (a[begin1] < a[begin2]) {tmp[index++] = a[begin1++];}else {tmp[index++] = a[begin2++];}}	while (begin1 <= end1) {       //把剩下还没插入tmp的,插入进去tmp[index++] = a[begin1++];}while (begin2 <= end2) {       //把剩下还没插入tmp的,插入进去tmp[index++] = a[begin2++];}//拷贝回原数组//source   dest     拷贝的数组大小memcpy(a+begin,tmp+begin,sizeof(DataType)*(end-begin+1));
}void MergeSort(DataType* a, int n) {DataType* tmp = (DataType*)malloc(sizeof(DataType) * n);     //开辟新的数组(临时存放)用于归并排序过程if (tmp == NULL) {perror("malloc fail");return;}//将 待排序的数组、归并过程用的tmp临时数组、归并范围 传过去_MergeSort(a, tmp, 0, n - 1);         //因为 主函数中有malloc tmp的操作,若递归调用主函数,则每次调用都会malloc,再free 是对空间上的浪费//因此用子函数进行递归 【_子函数】free(tmp);
}


(4)归并排序效率分析

1)时间复杂度 O(N*logN)

二分 有 logN 层 ,也正是因为是logN层,递归深度不会太深,所以不用考虑非递归,当然非递归也能实现。
每层有N个数进行归并排序

=>N*logN
在这里插入图片描述

2)空间复杂度 O(N)

开辟了个 空间大小为N的 新的数组,用于归并有序的过程。
在这里插入图片描述
在原数组上归并会出现什么问题:

  1. 会覆盖数据
  2. 最小的1换到8的位置后,8和7就不再保持有序了。

稳定性:稳定



二、归并排序的非递归实现

归并排序是 二分的思想 => logN层 => 递归不会太深、且现编译器优化后,递归、非递归的性能差距没有那么大了 =>所以不用考虑非递归,但非递归实现也不难。下面带大家简单实现一下。

(1) 关于递归的缺点的讨论

递归的缺点:递归消耗栈帧,递归的层数太深,容易爆栈。
【栈的空间比较小,在x86(32位)环境下,只有8M。(对比同一环境下的堆,则有2G+)。因为平时函数调用开不了多少个栈帧。理论上递归深度>1w 可能就会爆 ,但实际上5k左右就爆掉了】

这时就需要改非递归了

★递归—>非递归

  1. 改循环
  2. 利用 [ 数据结构 ] 栈(本质上是通过malloc 在堆上开辟的内存空间,内存空间足够大)
  3. 递归逆着来求(如斐波那契数列逆着来求也是可行的)【归并排序的非递归实现 也是个很好的例子】
    在这里插入图片描述而归并排序的非递归实现则是用到了其中的第三点 。


(2) 归并排序 非递归算法实现思路

虽说不是递归,是递归的逆序版。是直接从最深层次,逆序回去,直接开始归并排序,免去了向下深入递归。虽说不是递归,但也算是递归的思路的另一个种实现。
在这里插入图片描述

  1. 开辟新的数组(临时存放)用于归并排序过程
  2. int gap=1;gap*=2【gap控制归并的范围:11归并,22归并,44归并】
  3. for (int i = 0; i < n; i += 2 * gap) { 【i 控制进行比较轮到的组号,控制进行归并的组号】
  4. 归并完一轮,将归并好的有序数组拷贝回原数组memcpy 。
  5. 进入新的一轮归并,直至gap>n则归并完成

☆注意的两个情况
6. if (begin2 >= n) { break; } 第二组不存在,这一组不用归并了
7. if (end2 > n) { end2 = n - 1; } 第二组右边界越界问题,修正一下
在这里插入图片描述



(3)码源详解

//归并排序——非递归版 :从最底层开始,逆着往回求(如同斐波那契)
void MergeSortNonR(DataType* a,int n) {DataType* tmp = (DataType*)malloc(sizeof(DataType) * n);     //开辟新的数组(临时存放)用于归并排序过程if (tmp == NULL) {perror("malloc fail");return;}int gap = 1;while (gap < n) {                                        //gap控制 11归并,22归并,44归并//i控制进行比较轮到的组号,控制归并的组号for (int i = 0; i < n; i += 2 * gap) {               //可以通过画出数组,在草稿纸上演示,理清要比较的数begin1、end1、begin2、end2之间和i、gap的数量关系//[begin1,end1][begin2,end2]归并               int begin1 = i; int end1 = i + gap - 1;          //-1 控制下标的边界int begin2 = i + gap; int end2 = i + 2 * gap - 1;//如果第二组不存在,这一组不用归并了if (begin2 >= n) {break;}//第二组右边界越界问题,修正一下if (end2 > n) {end2 = n - 1;}int index = i;while (begin1 <= end1 && begin2 <= end2) {           //&& 其中一组不满足了条件了(其中一个数组遍历完了)就不再继续,就跳出循环  if (a[begin1] < a[begin2]) {                     //两个数组比对,小的放进去tmp[index++] = a[begin1++];}else{tmp[index++] = a[begin2++];}}while (begin1 <= end1) {                         //把剩下的没遍历进去的数组剩余的部分 遍历进去tmp[index++] = a[begin1++];}while (begin2 <= end2) {tmp[index++] = a[begin2++];}//拷贝回原数组//通过a+i、tmp+i来找到要拷贝数组部分的对应下标memcpy(a + i, tmp + i,(end2-i+1)*sizeof(DataType));}printf("\n");gap *= 2;                                            //gap控制总体归并}free(tmp);
}


(4)运行结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/179877.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分享一个自己写的免费的微信聊天记录提取软件 2023.11.03

有什么办法可以导出与某个人的微信聊天记录&#xff1f; 只想导出与某个微信好友的聊天记录&#xff0c;有办法做到吗&#xff1f;导出所有的话&#xff0c;文件太大了&#xff0c;只想导出与其中一个人的&#xff0c;求大神教。 我的需求和上面这个人的比较类似&#xff0c;因…

JMM讲解

一&#xff1a;为什么要有JMM&#xff0c;它为什么出现&#xff1f; CPU的运行并不是直接操作内存而是先把内存里面的数据读到缓存&#xff0c;而内存的读和写操作的时候会造成不一致的问题。JVM规范中试图定义一种Java内存模型来屏蔽掉各种硬件和操作系统的内存访问差异&…

基于深度学习的目标检测算法 计算机竞赛

文章目录 1 简介2 目标检测概念3 目标分类、定位、检测示例4 传统目标检测5 两类目标检测算法5.1 相关研究5.1.1 选择性搜索5.1.2 OverFeat 5.2 基于区域提名的方法5.2.1 R-CNN5.2.2 SPP-net5.2.3 Fast R-CNN 5.3 端到端的方法YOLOSSD 6 人体检测结果7 最后 1 简介 &#x1f5…

公会发展计划(GAP):经过实战考验的 Web3 任务模式

2020 年 12 月&#xff0c;Yield Guild Games 踏上了一段征程&#xff0c;以表彰兢兢业业的 Web3 游戏玩家所付出的时间和努力&#xff0c;同时为他们提供利用自己的技能促进个人成长的机会。这一旅程的第一步是于 2022 年 7 月推出的公会发展计划&#xff08;GAP&#xff09;。…

基于顺序表实现的可存储性通讯录!!!

基于顺序表实现的通讯录 通讯录的基本功能 顺序表顺序表的部分变量修改修改处一修改处二修改处三 头文件 Contact.h通讯录自定义结构体 功能实现 源文件 Contact.c读取文件中联系人的信息 void ContactReadFile(contact* pcon)保存到文件 void ContactSave(contact* pcon) 测试…

高德地图撒点组件

一、引入amap地图库 - public/index.html <script type"text/javascript">window._AMapSecurityConfig {securityJsCode: 地图密钥 }</script><scripttype"text/javascript"src"https://webapi.amap.com/maps?v1.4.8&key111111…

基于单片机的智能鱼缸控制系统的设计与实现

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、开发技术和原理的相关知识2.1开发设计目标2.2 开发设计使用技术和原理2.2.1嵌入式技术2.2.2传感器技术 二、基于单片机的智能鱼缸控制系统的总体设计3.1智能鱼缸控制系统的基本组成3.1.1系统的构成部分3.2需求…

【生物信息学】单细胞RNA测序数据分析:计算亲和力矩阵(基于距离、皮尔逊相关系数)及绘制热图(Heatmap)

文章目录 一、实验介绍二、实验环境1. 配置虚拟环境2. 库版本介绍 三、实验内容0. 导入必要的库1. 读取数据集2. 质量控制&#xff08;可选&#xff09;3. 基于距离的亲和力矩阵4. 绘制基因表达的Heatmap5. 基于皮尔逊相关系数的亲和力矩阵6. 代码整合 一、实验介绍 计算亲和力…

【ElasticSearch系列-04】ElasticSearch的聚合查询操作

ElasticSearch系列整体栏目 内容链接地址【一】ElasticSearch下载和安装https://zhenghuisheng.blog.csdn.net/article/details/129260827【二】ElasticSearch概念和基本操作https://blog.csdn.net/zhenghuishengq/article/details/134121631【三】ElasticSearch的高级查询Quer…

动态路由协议OSPF项目部署(二)

1. 静态和动态路由的区别&#xff1b; 2. OSPF协议通信过程与部署&#xff1b; 3. OSPF协议在项目上的应用场景 - OSPF - 开放式最短路径优先 - 一个动态路由协议 - 路由器转发数据 - 路由器需要一张地图 - 路由表 - 路由表如何构建的&#xff1f; - 依靠手动 或…

python脚本监听域名证书过期时间,并将通知消息到钉钉

版本一&#xff1a; 执行脚本带上 --dingtalk-webhook和–domains后指定钉钉token和域名 python3 ssl_spirtime.py --dingtalk-webhook https://oapi.dingtalk.com/robot/send?access_tokenavd345324 --domains www.abc1.com www.abc2.com www.abc3.com脚本如下 #!/usr/bin…

面试算法53:二叉搜索树的下一个节点

题目 给定一棵二叉搜索树和它的一个节点p&#xff0c;请找出按中序遍历的顺序该节点p的下一个节点。假设二叉搜索树中节点的值都是唯一的。例如&#xff0c;在图8.9的二叉搜索树中&#xff0c;节点8的下一个节点是节点9&#xff0c;节点11的下一个节点是null。 分析&#xf…

Qt封装的Halcon显示控件,支持ROI绘制

前言 目前机器视觉ROI交互控件在C#上做的比较多&#xff0c;而Qt上做的比较少&#xff0c;根据作者 VSQtHalcon——显示图片&#xff0c;实现鼠标缩放、移动图片的文章&#xff0c;我在显示和移动控件的基础上&#xff0c;增加了ROI设置功能&#xff0c;并封装成了一个独立的Q…

领星ERP如何无需API开发轻松连接OA、电商、营销、CRM、用户运营、推广、客服等近千款系统

领星ERP&#xff08;LINGXING&#xff09;是一款专业的一站式亚马逊管理系统&#xff0c;帮助卖家构建完整的数据化运营闭环。&#xff0c;致力于为跨境电商卖家提供精细化运营和业财一体化的解决方案。 官网&#xff1a;https://erp.lingxing.com 集简云无代码集成平台&…

轻量封装WebGPU渲染系统示例<13>- 屏幕空间后处理效果(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/main/src/voxgpu/sample/ScreenPostEffect.ts 此示例渲染系统实现的特性: 1. 用户态与系统态隔离。 细节请见&#xff1a;引擎系统设计思路 - 用户态与系统态隔离-CSDN博客 2. 高频调用与低频调用隔离。…

轧钢厂安全生产方案:AI视频识别安全风险智能监管平台的设计

一、背景与需求 轧钢厂一般都使用打包机对线材进行打包作业&#xff0c;由于生产需要&#xff0c;人员需频繁进入打包机内作业&#xff0c;如&#xff1a;加护垫、整包、打包机检修、调试等作业。在轧钢厂生产过程中&#xff0c;每个班次生产线材超过300件&#xff0c;人员在一…

腾讯云优惠券是什么?腾讯云优惠券怎么领取?

腾讯云是腾讯集团倾力打造的云计算品牌&#xff0c;为了吸引用户上云&#xff0c;经常推出各种优惠活动&#xff0c;其中就包括腾讯云优惠券。 1、腾讯云优惠券解释说明 腾讯云优惠券是腾讯云的一种优惠凭证&#xff0c;包括代金券和折扣券&#xff0c;领券之后新购、续费、升…

证明char是定长的?

证明char是定长的&#xff1f; 大部分博客都在讲解char和varchar区别的时候都谈到char为定长&#xff0c;varchar为变长。 但是怎么证明char为定长呢&#xff1f; 下面是我证明的过程。 创建CHAR列&#xff1a;首先&#xff0c;创建一个CHAR列&#xff0c;指定其长度。例如&…

基于Tensorflow卷积神经网络玉米病害识别系统(UI界面)

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 Tensorflow是一个流行的机器学习框架&#xff0c;可用于训练和部署各种人工智能模型。玉米病害识别系统基于Tensorf…

毕业设计-课程设计-基于python+django+vue开发的外卖点餐网站

文章目录 源码下载地址项目介绍项目功能界面预览项目备注毕设定制&#xff0c;咨询 源码下载地址 点击下载源码 项目介绍 该系统是基于pythondjango开发的外卖点餐系统。适用场景&#xff1a;大学生、课程作业、毕业设计。学习过程中&#xff0c;如遇问题可以在github给作者…