【排序】归并排序

归并排序

  • 动图演示:

在这里插入图片描述

  • 基本思想:分治思想

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

假设我们有左右两块有序区间的数组,可以对它直接进行合并。此时我们需要借助第三方数组,一次比较两块区间的起始位置,把小的那个放到新数组,随后依次比较,小的就放新数组,一直到结束。

但是现在存在一个问题,上述条件是假设了左半区间和右半区间有序,但是原先数组是无序的,也就是左半区间和右半区间均无序。怎么才能达到左半区间和右半区间有序最后再归并成整体有序呢?这就体现到了分治的思想了,将数组一直分,分到1个1个的,归并成有序变成2个2个的,然后归并成有序成4个4个的,最后再4个4个的归并成有序,最终至整体有序。

  • 画图解析其完整的归并过程:

在这里插入图片描述

这里我们先用代码实现其分解递归的过程,并用打印法表示其结果:

在这里插入图片描述

画图演示其部分递归分治的过程:

在这里插入图片描述

  • 总代码如下:
void _MergeSort(int* a, int begin, int end, int* tmp)
{if (begin >= end)return; //区间不存在就返回int mid = (begin + end) / 2;//[begin, mid] [mid+1, end]_MergeSort(a, begin, mid, tmp); //递归左半_MergeSort(a, mid + 1, end, tmp); //递归右半//归并[begin, mid] [mid+1, end]//printf("归并[%d,%d][%d,%d]\n", begin, mid, mid + 1, end);int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int index = begin;while (begin1 <= end1 && begin2 <= end2){//将较小的值放到tmp数组里头if (a[begin1] < a[begin2]){tmp[index++] = a[begin1++];}else{tmp[index++] = a[begin2++];}}//如若begin2先走完,把begin1后面的元素拷贝到新数组while (begin1 <= end1){tmp[index++] = a[begin1++];}//如若begin1先走完,把begin2后面的元素拷贝到新数组while (begin2 <= end2){tmp[index++] = a[begin2++];}//归并结束后,把tmp数组拷贝到原数组memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));
}//归并排序
void MergeSort(int* a, int n)
{//malloc一块新数组int* tmp = (int*)malloc(sizeof(int) * n);assert(tmp);_MergeSort(a, 0, n - 1, tmp);free(tmp);
}

归并排序非递归

  • 思想:

归并的非递归不需要借助栈,直接使用循环即可。递归版中我们是对数组进行划分成最小单位,这里非递归我们直接把它看成最小单位进行归并。我们可以通过控制间距gap来完成,先看图:

在这里插入图片描述

上述情况其实是在理想状态下可行的,只要数组长度不是2的次方倍都会出现问题,先简要看下理想状态下的伪代码,并用printf打印下归并过程:

在这里插入图片描述

再强调一遍,只要数组长度不是2的次方倍都会出现问题,像上述长度为8没有问题,那如若长度为6呢?

在这里插入图片描述

当长度为6不再是2的次方数时就运行出现问题了,综上我们需要考虑下极端情况:根据上述的区间范围,我们可以总结出以下三个可能会出现越界的情况:

  1. end1越界。
  2. begin2越界。
  3. end2越界。

1、end2越界:

在这里插入图片描述

2、begin2和end2均越界:

在这里插入图片描述

3、end1和begin2和end2均越界 :

在这里插入图片描述

综上,我们需要单独对这些极端情况处理。

//end1越界,修正即可
if (end1 >= n)
{end1 = n - 1;
}
//begin2越界,第二个区间不存在
if (begin2 >= n)
{begin2 = n;end2 = n - 1;
}
//begin2 ok,end2越界,修正下end2即可
if (begin2 < n && end2 >= n)
{end2 = n - 1;
}
  • 总代码如下:
//归并非递归
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);assert(tmp);int gap = 1;while (gap < n){//分组归并,间距为gap是一组,两两归并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;//end1越界,修正即可if (end1 >= n){end1 = n - 1;}//begin2越界,第二个区间不存在if (begin2 >= n){begin2 = n;end2 = n - 1;}//begin2 ok,end2越界,修正下end2即可if (begin2 < n && end2 >= n){end2 = n - 1;}printf("归并[%d,%d][%d,%d]\n", begin1, end1, begin2, end2);int index = i;while (begin1 <= end1 && begin2 <= end2){//将较小的值放到tmp数组里头if (a[begin1] < a[begin2]){tmp[index++] = a[begin1++];}else{tmp[index++] = a[begin2++];}}//如若begin2先走完,把begin1后面的元素拷贝到新数组while (begin1 <= end1){tmp[index++] = a[begin1++];}//如若begin1先走完,把begin2后面的元素拷贝到新数组while (begin2 <= end2){tmp[index++] = a[begin2++];}}memcpy(a, tmp, n * sizeof(int));gap *= 2;}free(tmp);
}

归并排序特性总结

1、归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。

2、时间复杂度:O(N*logN)。

3、空间复杂度:O(N)。

4、稳定性:稳定 。

内排序和外排序

在排序中,分为内排序和外排序,简单了解下其概念:

  • 内排序:数据量较少,在内存中进行排序。
  • 外排序:数据量很大,在磁盘上进行排序。

而我们前面学习的排序中,归并排序既可作为内排序,也可作为外排序,而其它几个排序只能是内排序,这也就说明了在处理数据量很大时,采用归并排序才能解决,其它排序不可。

如若我要排10亿个整数,就只能使用归并排序了,现在来简要算下其占比大小:

  • 1G = 1024MB
  • 1MB = 1024KB
  • 1KB = 1024Byte
  • 综上1G = 102410241024Byte,而10亿个整数40亿Byte,所以10亿个整数占4G

现在有10亿个整数(4G)的文件,只给你1G的运行内存,请对文件中的10亿个数进行排序。

核心思想: 数据量大,加载不到内存。想办法控制两个有序文件,两个有序文件归并成一个更大的有序文件。可以把这4G的文件分成4等份,每一份1G,分别读到内存进行归并排序,排完后再写回到磁盘小文件。

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

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

相关文章

小白学Halcon100例:如何应用极坐标的展开及逆变换?

这里写目录标题 什么是极坐标系?在halcon中对应的算子halcon实例程序输出结果:原图什么是极坐标系? 1、极坐标系(polar coordinates)是指在平面内由极点、极轴和极径组成的坐标系。在平面上取定一点O,称为极点。从O出发引一条射线Ox,称为极轴。再取定一个单位长度,通常…

“操作符大揭秘:一篇文章让你秒懂所有!”

目录 1. ⼆进制介绍 2. 原码、反码、补码 3. 移位操作符 4. 位操作符&#xff1a;&、|、^ 5. 逗号表达式 6. 下标访问[]、函数调⽤() 7. 操作符的属性&#xff1a;优先级、结合性 8. 整型提升 9. 算术转换 10. 表达式求值 正文开始&#xff1a; 1. ⼆进制 其实我…

Mysql的安装、使用、优势与教程

一.安装 1.在小皮的设置界面检测3306端口&#xff0c;保障3306端口可用&#xff1b; 2、在小皮的首面界面&#xff0c;启动MySQL&#xff1b; 3、进行环境变量设置&#xff0c;找到MySQL的路径&#xff0c;进行复制&#xff1b; 4、在Windows的搜索栏内&#xff0c;输入“环境…

区块链互操作协议

1. 引言 Alexei Zamyatin等人2019年论文 SoK: Communication Across Distributed Ledgers。 参考资料 [1] 2019年论文 SoK: Communication Across Distributed Ledgers [2] A list of blockchain-related SoK papers [3] 2021年视频 FC21: SoK: Communica…

【机器学习】数据清洗之处理异常点

&#x1f388;个人主页&#xff1a;甜美的江 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步…

数据结构——lesson2线性表和顺序表

目录 前言 一、顺序表是什么&#xff1f; 1. 静态顺序表&#xff1a;使用定长数组存储元素 2. 动态顺序表&#xff1a;使用动态开辟的数组存储。 二、接口实现 1.动态顺序表存储 2.基本增删查改接口 (1)初始化顺序表 (2)顺序表摧毁 (3)检查空间 (4)顺序表打印 (5)顺…

第四篇【传奇开心果微博系列】Python微项目技术点案例示例:美女颜值判官

传奇开心果微博系列 系列微博目录Python微项目技术点案例示例系列 微博目录一、微项目目标二、雏形示例代码三、扩展思路四、添加不同类型的美女示例代码五、增加难度等级示例代码六、添加特殊道具示例代码七、设计关卡系统示例代码八、添加音效和背景音乐示例代码九、多人游戏…

C++ 音视频原理

本篇文章我们来描述一下音视频原理 音视频录制原理: 下面是对这张思维导图的介绍 摄像头部分: 麦克风采集声音 摄像头采集画面 摄像头采集回来的数据可以用RGB也可以用YUV来表示 图像帧帧率 一秒能处理多少张图像 图像处理 &#xff1a;调亮度 图像帧队列 :意思是将数据取…

简单介绍源程序执行方式

源程序执行方式 编译和解释 程序设计语言能够把算法翻译成机器能够理解的可执行程序。这里将计算机不能直接执行的非机器语言源程序翻译成能直接执行的机器语言的语言翻译程序称为语言处理程序 源程序&#xff1a;用各种程序设计语言编写的程序称为源程序&#xff0c;计算机不…

C++ //练习 6.6 说明形参、局部变量以及局部静态变量的区别。编写一个函数,同时用到这三种形式。

C Primer&#xff08;第5版&#xff09; 练习 6.6 练习 6.6 说明形参、局部变量以及局部静态变量的区别。编写一个函数&#xff0c;同时用到这三种形式。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 /********************…

分享87个CSS3特效,总有一款适合您

分享87个CSS3特效&#xff0c;总有一款适合您 87个CSS3特效下载链接&#xff1a;https://pan.baidu.com/s/1CAxe8nPBzXvH7Nr6B_U72Q?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不…

更新至2022年,迪博上市公司内部控制指数、分项指数、评级等数据

更新至2022年&#xff0c;上市公司迪博内部控制指数、分项指数、评级等数据 1、时间&#xff1a;更新至2022年&#xff0c;四份数据&#xff0c;具体时间见下文 2、范围&#xff1a;上市公司 3、具体数据&#xff1a; 2000-2022年上市公司内部控制指数评级及评分数据 2007…

【JVM篇】什么是jvm

文章目录 &#x1f354;什么是Java虚拟机&#x1f6f8;Java虚拟机有什么用&#x1f339;Java虚拟机的功能&#x1f388;Java虚拟机的组成 &#x1f354;什么是Java虚拟机 JVM指的是Java虚拟机&#xff0c;本质上是一个运行在计算机上的程序&#xff0c;可以运行 Java字节码文件…

NAT——网络地址转换、NAPT

网络地址转换 NAT (Network Address Translation) 1994 年提出。 需要在专用网连接到互联网的路由器上安装 NAT 软件。 装有 NAT 软件的路由器叫做 NAT路由器&#xff0c;它至少有一个有效的外部全球 IP 地址。 所有使用本地地址的主机在和外界通信时&#xff0c;都要在 NA…

【教程】MySQL数据库学习笔记(三)——数据定义语言DDL(持续更新)

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【MySQL数据库学习】系列文章 第一章 《认识与环境搭建》 第二章 《数据类型》 第三章 《数据定义语言DDL》 文章目录 【MyS…

docker 1:介绍

docker 1&#xff1a;介绍 docker解决哪些问题&#xff1a; 传统APP在安装到不同电脑的时候可能会遇到依赖问题&#xff0c;比如缺少VS 20xx&#xff0c;软件无法运行”的情况。docker使用容器技术将软件 依赖​打包为image包发布&#xff0c;解决了依赖问题。docker有一个官…

MATLAB|【免费】高比例可再生能源电力系统的调峰成本量化与分摊模型

目录 主要内容 部分代码 结果一览 下载链接 主要内容 程序复现文献《高比例可再生能源电力系统的调峰成本量化与分摊模型》&#xff0c;从净负荷波动的角度出发&#xff0c;建立了调峰成本的量化与分摊模型&#xff0c;构造了无调峰需求的替代场景&#xff0c;将…

在Ubuntu22.04上部署FoooCUS2.1

Fooocus 是一款基于 Gradio的图像生成软件&#xff0c;Fooocus 是对 Stable Diffusion 和 Midjourney 设计的重新思考&#xff1a; 1、从 Stable Diffusion 学习&#xff0c;该软件是离线的、开源的和免费的。 2、从 Midjourney 中学到&#xff0c;不需要手动调整&#xff0c;…

优先级队列(堆)_PriorityQueue

前言 想要看如何使用可以通过目录跳转到 PriorityQueue的使用 优先级队列 概念 队列是一种先进先出(FIFO)的数据结构&#xff0c;但有些情况下&#xff0c;操作的数据可能带有优先级&#xff0c;一般出队 列时&#xff0c;可能需要优先级高的元素先出队列&#xff0c;该中场…

前端秘法引言(配置vscode, 以及html的基础)

目录 一.配置环境vscode 二.配置插件 三.vscode的实用小技巧 四.标题段落换行标签 五.格式化标签 一.配置环境vscode vscode官网https://code.visualstudio.com/ 点击右上角的download 根据不同的操作系统进行下载安装,我这里选的是Windows x64 安装好后打开,点击左上角的…