排序——归并排序

归并排序和快排一样, 都是一种利用二叉树分治思想实现的排序。同时归并排序也和快排一样有递归归并排序和非递归归并排序两种。 本节主要复习归并排序, 并且两种实现方式都会复习到。

递归归并

要实现递归归并排序的代码。 我们首先需要理解递归归并排序的思想。 递归归并的过程如下:

假如有一个数组

int a[10] = { 9, 0, 7, 5, 4, 3, 1, 2, 8, 6 };
int sz = sizeof(a) / sizeof(a[0]);

 要对这个数组进行排序。 

那么利用归并的分治思想, 就是先将数据进行如图划分。

图中每个子节点都标识范围内的数据。 比如9 0 7就表示0倒2这个区间内的三个数据。然后进行后序归并。 

 代码实现如下

首先创建一个子函数, 方便递归, _MergeSort就是我们要实现的归并排序过程

void MergeSort(int* a, int sz) 
{int* tmp = (int*)malloc(sizeof(int) * sz);//_MergeSort(a, 0, sz - 1, tmp);free(tmp);
}

//归并排序递归版本
void _MergeSort(int* a, int left, int right, int* tmp) 
{if (left >= right)//如果区间不存在或者只剩下一个节点, 直接返回。 {return;}//int mid = (left + right) / 2;//让区间中分_MergeSort(a, left, mid, tmp);//从左边开始归并。 两两一组进行归并。_MergeSort(a, mid + 1, right, tmp);//两俩个一组//后续归并。所以先递归再进行归并int begin1 = left;//对中分点的左右两个区间进行归并。 begin1 为第一个区间左边int end1 = mid;//end1为左区间右边。int begin2 = mid + 1;//begin2为右区间左边int end2 = right;//end2为右区间右边int j = left;//让j从左区间左边开始控制, j是控制tmp拷贝数组的拷贝。 在一块区间进行归并, 就应该将这块区间的数据拷贝到tmp的对应区间上while (begin1 <= end1 && begin2 <= end2) //只要两个区间都没有超出去, 就进行判断,那个数据小, 拷贝哪个。{if (a[begin1] < a[begin2]) {tmp[j++] = a[begin1++];}else {tmp[j++] = a[begin2++];}}while (begin1 <= end1) //如果左区间还没完, 就继续拷贝{tmp[j++] = a[begin1++];}while (begin2 <= end2) //如果右区间还没完, 就继续拷贝{tmp[j++] = a[begin2++];}memcpy(a + left, tmp + left, sizeof(int) * (right - left + 1));}

非递归归并

进行非递归归并, 归并的过程也是一种分治, 不过利用了一个gap值控制每次归并的分治区间大小。直接上代码


//归并非递归
void MergeSortRno(int* a, int sz) 
{int* tmp = (int*)malloc(sizeof(int) * sz);//int gap = 1;while (gap < sz) {gap *= 2;}
}

着段代码的意思是, 从区间为1开始, 归并之后。 区间乘以二。然后再进行归并。 然后再乘以二, 再进行归并。 最后一次归并可能很巧合gap就是sz / 2,这个时候不需要进行其他操作。 但是如果最后一次归并gap 比 sz / 2大的话。 那么就需要额外的操作。 这个问题会放到后面说, 这里先不讨论。 先将归并的内容实现。

//归并非递归
void MergeSortRno(int* a, int sz) 
{int* tmp = (int*)malloc(sizeof(int) * sz);//int gap = 1;while (gap < sz) {for (int i = 0; i < sz; i += 2 * gap) {}gap *= 2;}
}

归并的时候每gap是一个区间, 每两个区间进行归并。 当gap很小的时候, 很显然这个数组一定不是只有一两个区间。 这些区间进行归并的时候, 应该将所有的区间两两归并。 从下标为0, 向后依次进行。 

这里for循环就是来完成这个操作的,如图为gap为1的时候进行的归并, 每两个区间进行归并,一共五组, 从左到右依次进行:

然后具体的递归过程就和递归归并的归并过程大概是一样的了。

//归并非递归
void MergeSortRno(int* a, int sz) 
{int* tmp = (int*)malloc(sizeof(int) * sz);//int gap = 1;while (gap < sz) {for (int i = 0; i < sz; i += 2 * gap) {//归并过程int begin1 = i;int end1 = i + gap - 1;int begin2 = i + gap;int end2 = i + 2 * gap - 1;if (end1 > sz || begin2 > sz) {break;}if (end2 > sz) {end2 = sz - 1;}int j = i;while (begin1 <= end1 && begin2 <= end2) {if (a[begin1] < a[begin2]){tmp[j++] = a[begin1++];}else {tmp[j++] = a[begin2++];}}while (begin1 <= end1) {tmp[j++] = a[begin1++];}while (begin2 <= end2) {tmp[j++] = a[begin2++];}memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));//请注意这里}gap *= 2;}
}

这里之所以说是大概, 就是因为这里有个超出范围的坑。 我们进行非递归归并的过程过程中可能遇到这种情况。

就比如我们这个十个大小的数组,当gap为2的时候范围就出问题了。如图:

当gap为二的时候, 第一组进行归并的是0-1区间和2-3区间归并。 第二组区间分别是4-5和6-7归并。 第三组本来应该是8-9和10-11, 但是10-11不在数组里面。我们是没有访问权限的。

所以这就出问题了。 那么解决问题的方式就是对着种越界情况进行判断。

我们分析这种越界情况有几种?

第一种:第一个区间的右区间超出范围, 这种显然不成立。 

第二种:第二个区间的左区间超出范围, 当第一个区间的右区间超出时这种就一定成立。

第三种:第二个区间的左区间没有超范围, 也就是第一种和第二种情况都不符合的情况下右区间超出了范围。 

那么解决方法就是这几行代码:

	if (end1 > sz || begin2 > sz) {break;}if (end2 > sz) {end2 = sz - 1;}

首先第一个if的意思就是第一种情况或者第二种情况。 这个时候break就行了。 最后一组的第二个区间不存在, 不需要进行归并, 直接跳出循环就行了。 

第二个if就是在第一种情况合第二种情况都不符合的情况下可能符合。 这个时候最后一组的第二个区间内有数据, 但是和其他的区间数据个数不同, 虽然不同,但它也是可以进行归并的。 所以我们只要修改右区间的范围就行了。

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

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

相关文章

PyTorch-神经网络

神经网络&#xff0c;这也是深度学习的基石&#xff0c;所谓的深度学习&#xff0c;也可以理解为很深层的神经网络。说起这里&#xff0c;有一个小段子&#xff0c;神经网络曾经被打入了冷宫&#xff0c;因为SVM派的崛起&#xff0c;SVM不了解的同学可以去google一下&#xff0…

stm32触发硬件错误位置定位

1.背景 1. 项目中&#xff0c;调试过程或者测试中都会出现程序跑飞问题&#xff0c;这个时候问题特别难查找。 2. 触发硬件错误往往是因为内存错误。这种问题特别难查找&#xff0c;尤其是产品到了测试阶段&#xff0c;而这个异常复现又比较难的情况下&#xff0c;简直头疼。…

(css)element-ui表格行图片点击放大且可调整preview-src-list大图预览样式

(css)element-ui表格行图片点击放大且可调整preview-src-list大图预览样式 效果&#xff1a; 常规写法&#xff1a; <el-table-column prop"display" label"展示效果" align"center"><template slot-scope"scope"><e…

IEEE Transactions on Industrial Electronics工业电子TIE修改稿注意事项及提交须知

一、背景 兔年末投了一篇TIE&#xff0c;手稿初次提交的注意事项也整理成了博客IEEE Transactions on Industrial Electronics工业电子TIE论文投稿须知&#xff0c;获得了许多点赞和收藏。最近也收到了审稿结果&#xff0c;给的意见是大修major revision&#xff0c;总之只要不…

国内chatgpt写作软件,chatgpt国内使用

随着人工智能技术的不断发展&#xff0c;国内涌现出了一些基于ChatGPT模型的写作软件&#xff0c;这些软件不仅能够实现智能化的文章写作&#xff0c;还支持批量生成各种类型的文章。本文将深入探讨国内ChatGPT写作软件&#xff0c;以及它们在批量文章创作方面的应用与优势。 C…

C#使用iText7给PDF文档添加书签

上一篇文章将SqlSugar官网文档中每个链接对应的网页生成独立PDF文档再合并为单个PDF文档&#xff0c;但是没有书签&#xff0c;八百多页的内容查找和跳转都不方便&#xff0c;本文学习和使用iText7给PDF文档添加多级书签。   添加多级书签分为两大步骤&#xff1a;1&#xff…

选项 打光 试题总结

试题1 被测物体100100mm&#xff0c;精度要求被测物体 &#xff0c;精度要求0.1mm&#xff0c;相机距被测物体在200&#xff5e;320mm之间&#xff0c;要求选择合适的相机和镜头&#xff1f; 分析如下&#xff1a; 通常我们用的相机靶面是4:3 的所以我们要用短边来计算视场&am…

【element-ui】el-select multiple多选,表单校验问题解决方法

在项目开发过程中发现&#xff0c;el-select设置了multiple支持多选属性之后&#xff0c;el-select赋值之后&#xff0c;表单校验不通过 解决思路及解决方法&#xff1a; 1、首先看看v-model 、prop属性、rules校验是否正确&#xff0c;这里注意el-select的rules校验的trigger…

具身智能计算系统,机器人时代的 Android | 新程序员

【导读】具身智能作为一种新兴的研究视角和方法论&#xff0c;正在刷新我们对智能本质及其发展的理解&#xff1a;传统的 AI 模型往往将智能视为一种独立于实体存在的抽象能力&#xff0c;而具身智能则主张智能是实体与其环境持续互动的结果。 本文深度剖析了具身智能计算系统…

第二篇【传奇开心果系列】Python的自动化办公库技术点案例示例:深度解读Pandas金融数据分析

传奇开心果博文系列 系列博文目录Python的自动化办公库技术点案例示例系列 博文目录前言一、Pandas 在金融数据分析中的常见用途和功能介绍二、金融数据清洗和准备示例代码三、金融数据索引和选择示例代码四、金融数据时间序列分析示例代码五、金融数据可视化示例代码六、金融数…

Linux设备模型(十) - bus/device/device_driver/class

四&#xff0c;驱动的注册 1&#xff0c;struct device_driver结构体 /** * struct device_driver - The basic device driver structure * name: Name of the device driver. * bus: The bus which the device of this driver belongs to. * owner: The module own…

uniapp开发android原生插件

一、下载原生开发SDK Android 离线SDK - 正式版 | uni小程序SDK (dcloud.net.cn)、 https://nativesupport.dcloud.net.cn/AppDocs/download/android.html 将开发uniappa原生android的插件解压到ben本地目录&#xff0c;目录结构如下&#xff1a; 接下就可以使用 UniPlugin-Hel…

第三百八十回

文章目录 1. 概念介绍2. 使用方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 013pickers2.gif 我们在上一章回中介绍了"如何实现Numberpicker"相关的内容&#xff0c;本章回中将介绍wheelChoose组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念…

蓝桥杯练习题——差分

1.空调 思路 1.区间同时加减 1&#xff0c;可以转换成一个差分数组两个端点的操作 2.用 p 减去 t 数组&#xff0c;得到要消除的数组 a&#xff0c;对 a 求差分数组 3.差分数组一正一负为一个操作&#xff0c;因为是把这个原数组区间加上了 1&#xff0c;单独的正负为一个操作…

Python把excel内容保存为图片(非统计图而是纯原表格数据)

一、引入 excel2img 库&#xff0c;没有的话使用 pip install excel2img进行安装 二、采用如下方法进行图片生成 excel文件名为&#xff1a;111.xlsx excel表格里面的sheet名称列表为 [Sheet1, Sheet2] 最终保存为以sheet名称.png的图片 支持跨表格合并项 import excel2i…

《手把手教你》系列技巧篇(十五)-java+ selenium自动化测试-元素定位大法之By xpath中卷(详细教程)

1.简介 按宏哥计划&#xff0c;本文继续介绍WebDriver关于元素定位大法&#xff0c;这篇介绍定位倒数二个方法&#xff1a;By xpath。xpath 的定位方法&#xff0c; 非常强大。 使用这种方法几乎可以定位到页面上的任意元素。 2.什么是xpath&#xff1f; xpath 是XML Path的…

Win11系统实现adb命令向安卓子系统安装APP

Win11系统实现通过adb命令向安卓子系统安装已下载好的apk包。 要实现以上目标&#xff0c;我们需要用到一个Android SDK 的组件Android SDK Platform-Tools &#xff01;这个组件呢其实是被包含在 Android Studio中的&#xff0c;如果你对安卓开发有所了解对此应该不会陌生&…

超全面!Linux学习资料大合集,21套从入门到进阶,看这篇就够了

本文将为那些渴望学习Linux&#xff0c;但又缺乏相应资料和方向的朋友&#xff0c;提供21套Linux优质资料&#xff0c;包含入门到进阶&#xff0c;希望能对大家有所帮助。 此合集内容及其丰富&#xff0c;涉及方面颇多&#xff0c;不仅适合Linux入门学习的朋友&#xff0c;运维…

Linux(CentOS)学习

一、认识Linux 1、如何修改Linux时区 2、配置固定IP 3、重启网络服务 3、小技巧快捷键 4、环境变量设置 5、Linux文件的上传和下载 6、压缩和解压 二、基础命令 1、目录命令 (1、)查看目录内容&#xff08;ls&#xff09; 1、ls //查看当前目录内容 2、- a //显示隐藏内容 3…

Web自动化测试平台开发---Automated_platform

一、项目简介 历时一个假期&#xff0c;Automated_platform 第一版完工&#xff0c;是一款基于po模式的自动化测试平台,采用后端技术为DjangoceleryRabbitMQmysql 配置mysql数据库&#xff0c;进行数据迁移后&#xff0c;运行项目后&#xff0c;即可成功访问http://127.0.0.1:8…