【排序算法】归并排序

一、定义:

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

二、递归思路:

 ✨✨首先根据定义,我们会发现和二叉树又又又联动了🤩🤩

归并排序是用分治思想,每一层递归上有三个步骤:
● 分解(Divide):将n个元素分成个含n/2个元素的子序列。
● 解决(Conquer):用合并排序法对两个子序列递归的排序。
● 合并(Combine):合并两个已排序的子序列得到排序结果。


 🚗🚗发现了吗???我们好像是先从根开始的,这说明了啥???先动左子树,再动右子树,再动根,这个不就是🤔后续遍历么?

✨没错,确实就是模仿的后续遍历实现递归

🎟️排序:也是划分区间进行哎,将一个数组整个区间分成2个区间,然后将2个区间变成有序的,不知道有有没有写过2个有序数组的合并这个OJ题??🧑‍🎓没写过也没问题,这里我们借助它的思路,2个有序数组的合并,创建第三方数组tmp,遍历2个数组,进行比较,谁小,谁的数据进入第三方数组tmp, 且下标加1,然后继续比较,直到有一方数组遍历结束,最后将剩下没有遍历完的数组中的数据放入tmp中👻👻

👻思路是这样的:

将数组分成2部分,其实相当于2个数组,这2个数组首先得是有序的,再进行有序数组的合并;

👉递归传递的是区间,区间相等即left==right时,不就只有一个数据,根本分不了区间了,此时可以看作就是有序的哦也就是👉画绿线的那一行

这也就是我们的结束条件:👉👉只有一个元素,递归结束,开始回推,回推的过程就开始合并2个有序数组的进行

 

✨✨ 首先我们对[0,1]这个区间二分,分成的区间都只有一个元素,可以看成有序,进行比较合并合并 ,回到上一层函数后,进入右边对[2,3]这个区间二分,同理,直接比较合并击即可🐸

🧑‍🎓🧑‍🎓🤔后续遍历是左、右子树然后是根节点,不就是回到10 6 7 1的这一层么,此时这里应该是如下所示的样子,然后对这个区间进行二分,分成的2个区间已然是有序的,进行2个数组合并即可,放到tmp中

 

放到tmp数组中之后,我们可以通过memcpy函数将tmp拷贝回原数组[0,3]这个区间;回推的过程依次类推

 

 传递的是a+left,因为我们要放的位置是根据区间来放的,改变的是这个区间里面数据的顺序,拷贝回去也只能是a的这个区间,不然会将别的数据弄丢

有一个需要注意的点:就是传区间时,左和右区间的传参有一定的讲究,只能这么传

如果另一种传法,会导致陷入死循环,至于原因,目前本人不是很太能讲清楚,就先不写了

三、非递归:

将递归变成迭代的思想

🧑‍🎓之前用栈是因为我们来模拟递归,但是这里进行排序是在回推的时候进行的,在这里栈已经不行了 🧑‍🎓

那就试试直接用循环写呗,还记得之前插入排序的gap嘛???

🤔这里我们用gap记录元素个数,一开始gap=1 ,一组里面一个元素

区间不就是👉👉这样的么

 然年第就是2个数归并

 四四归,但是我们的最右边凑不出来四组,怎么办🤔🤔仔细看,不归并也行呢??这个是有序数组,左边的归并后就是有序数组了,最后就是👉

 左边 和 右边 归并  

 

 ✨✨核心在于gap组的控制:gap 2倍2倍的长,但是不能超过数组长度,区间二分嘛,2个区间

begin1,en1   begin2和end2 就是二分的2区间,将这2个区间进行归并

✨ 这里的数据是偶数,如果是奇数了???先别急🤗这个写法会发生越界访问,出不了结果的

👉看看我打印的区间:第一行正常,第二行正常,第三行,[12,15]越界了,第四行[8,15]一部分越界了

 说明需要修改,卡看越界的特点,我们是【begin1,end1】和 【begin2,end2】2个区间归并

第三行越界的区间正好是begin2  是不是可以去处理一下这个区间,当begin2>=n时候,打破循环,前面【8,11】在上一层下来的时候已经归并好了的

 最后一层越界的是 end2,这里处理起来应该是要去修正,因为最后一行,要将[0,7][8,11]归并起来所以可以进行修正end2 = n-1

 

四、代码:

递归:

//子函数:实现递归
void _MergeSort(int* tmp, int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
    //防止栈溢出的写法,当然直接写(right+left)/2也行
	int mid = ((right-left)>>1)+left;
	_MergeSort(tmp, a, left, mid);
	_MergeSort(tmp, a, mid + 1,right);
	int begin1 = left;
	int end1 = mid;
	int begin2 = mid + 1;
	int end2 = right;
	int i = 0;
	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++];
	}
	memcpy(a + left, tmp, (right - left + 1)*sizeof(int));

}
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	_MergeSort(tmp, a, 0, n-1);
	free(tmp);
	tmp = NULL;
}

非递归:

//非递归归并
void MergeSortNonR(int* a, int n)
{
	//额外创造一个空间
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i+=2*gap)
		{
			int begin1 = i;
			int end1 = i + gap - 1;
			int begin2 = i + gap;
			int end2 = i + 2 * gap-1;
			int j = i;
			
			if (begin2>=n)
			{
				break;
			}	 
			if (end2 >= n)
			{
				end2 = n - 1;
			}
			printf("[%d,%d][%d,%d]", begin1, end1, begin2, end2);
			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));

		}
		putchar('\n');
		gap *= 2;
	}


	free(tmp);
	tmp = NULL;
}

✨期待你的关注

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

精益求精测径仪颜色也是一种工艺细节

首先&#xff0c;测径仪的颜色可以作为一种视觉标识&#xff0c;提升工作效率。在复杂的生产环境中&#xff0c;不同颜色的测径仪可以迅速区分不同型号、规格或功能的设备&#xff0c;减少误操作的可能性。同时&#xff0c;通过颜色搭配&#xff0c;还可以实现设备布局的美观与…

[数据集][图像分类]煤矿分类数据集351张4类别

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;351 分类类别数&#xff1a;4 类别名称:[“Anthracite”,“Bituminous”,“…

Qt应用程序发布

一、静态编译发布 1.0:以Release模式构建工程 1.1:查看当前构建生成路径,并将所生成的.exe单独拷贝出来 1.2:将可执行文件*.exe拷贝至任一目标文件夹:D:\Temporary\QQIF 2:查看安装Qt时发布工具windeployqt.exe所在的目录 windeployqt.exe在Qt开发套件的bin目录下。Qt的每…

一个可以自动生成随机区组试验的excel VBA小程序

在作物品种区域试验时&#xff0c;通常会采用随机区组试验设计&#xff0c;特制作了一个可以自动生成随机区组试验的小程序。excel参数界面如下&#xff1a; 参数含义如下&#xff1a; 1、生成新表的名称&#xff1a;程序将新建表格&#xff0c;用于生成随机区组试验。若此处为…

JavaScript 从入门到精通Object(对象)

文章目录 对象文本和属性方括号计算属性 属性值简写属性名称限制属性存在性测试&#xff0c;“in” 操作符“for…in” 循环像对象一样排序 总结✅任务你好&#xff0c;对象检查空对象对象属性求和将数值属性值都乘以 2 对象引用和复制通过引用来比较克隆与合并&#xff0c;Obj…

消息队列-ActiveMQ

异步技术 企业级应用中广泛使用的三种异步消息传递技术 版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。原文链接&#xff1a;https://blog.csdn.net/qq_55917018/article/details/122122218 三…

创建 MFC DLL-使用关键字_declspec(dllexport)

本文仅供学习交流&#xff0c;严禁用于商业用途&#xff0c;如本文涉及侵权请及时联系本人将于及时删除 从MFC DLL中导出函数的另一种方法是在定义函数时使用关键字_declspec(dllexport)。这种情况下&#xff0c;不需要DEF文件。 导出函数的形式为&#xff1a; declspec(dll…

libsystemctlm-soc项目分析

概述 libsystemctlm-soc项目是Xilinx的SystemC库。 环境安装 verilator安装 # Prerequisites: #sudo apt-get install git help2man perl python3 make autoconf g flex bison ccache #sudo apt-get install libgoogle-perftools-dev numactl perl-doc #sudo apt-get insta…

调用讯飞星火API实现图像生成

目录 1. 作者介绍2. 关于理论方面的知识介绍3. 关于实验过程的介绍&#xff0c;完整实验代码&#xff0c;测试结果3.1 API获取3.2 代码解析与运行结果3.2.1 完整代码3.2.2 运行结果 3.3 界面的编写&#xff08;进阶&#xff09; 4. 问题分析5. 参考链接 1. 作者介绍 刘来顺&am…

VL53L4CX TOF开发(2)----修改测距范围及测量频率

VL53L4CX TOF开发.2--修改测距范围及测量频率 概述视频教学样品申请完整代码下载测距范围测量频率硬件准备技术规格系统框图应用示意图生成STM32CUBEMX选择MCU串口配置IIC配置 XSHUTGPIO1X-CUBE-TOF1app_tof.c详细解释测量频率修改修改测距范围 概述 最近在弄ST和瑞萨RA的课程…

前端开发入门指南:掌握网页设计的第一课

UI设计与前端开发是相辅相成&#xff0c;UI设计可以视觉美化产品界面&#xff0c;而前端开发可以通过代码实现设计稿。作为UI设计师&#xff0c;如果画出来的图片美观方便对前端开发者非常有益。如果设计复比较难以实现&#xff0c;沟通就会变得更加困难。因此&#xff0c;UI设…

html+CSS+js部分基础运用14

熟悉插值{{}}的用法&#xff0c;在页面中显示下列内容。图1 插值语法的效果图 在页面中统计鼠标单机按钮的次数。【提示&#xff1a;v-on指令】&#xff0c;页面效果如下图所示&#xff1a;图2 统计效果图 3、①单击按钮可以修改黑体字。②通过调试工具vue-devtools修改黑体字。…

数据结构:并查集

数据结构&#xff1a;并查集 题目描述参考代码 题目描述 输入样例 5 5 C 1 2 Q1 1 2 Q2 1 C 2 5 Q2 5输出样例 Yes 2 3参考代码 #include <iostream>using namespace std;const int N 100010;int n, m; int p[N], sz[N];int find(int x) // 返回x的祖宗节点 路径…

AI网络爬虫:用GraphQL查询爬取动态网页数据

任务&#xff1a;爬取网站www.skillshare.com搜索结果页面数据&#xff1a; 查看网站的请求信息&#xff1a; 请求网址: https://www.skillshare.com/api/graphql 请求方法: POST 状态代码: 200 OK 远程地址: 127.0.0.1:10809 引荐来源网址政策: strict-origin-when-…

Go 群发邮件Redis 实现邮件群发

一、安装 go get github.com/go-redis/redis/v8 go get gopkg.in/gomail.v2 二、使用"gopkg.in/gomail.v2"群发 package mainimport (gomail "gopkg.in/gomail.v2" )func main() {// 邮件内容m : gomail.NewMessage()m.SetHeader("From", &qu…

实验11 OSPF协议配置

实验11 OSPF协议配置 一、OSPF单区域配置&#xff08;一&#xff09;原理描述&#xff08;二&#xff09;实验目的&#xff08;三&#xff09;实验内容&#xff08;四&#xff09;实验配置&#xff08;五&#xff09;实验步骤 二、OSPF多区域配置&#xff08;一&#xff09;原理…

44-5 waf绕过 - SQL注入绕WAF方法

环境准备: 43-5 waf绕过 - 安全狗简介及安装-CSDN博客然后安装sqlilabs靶场:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 一、双写绕过 打开sql靶场的第一关:http://127.0.0.1/sqli-labs-master/Less-1/?id=1 验证一下waf是否开启防…

创新指南|2024企业如何开启生成式AI创新?从5大应用场景和6步抓手

想要了解如何采用生成式AI来提高企业效率和竞争力&#xff1f;本指南将介绍如何采用生成式AI来实现数字化转型&#xff0c;并打造智能化商业模式。从5大应用场景和6大步骤切入&#xff0c;让您了解如何开启生成式AI创新。立即连线创新专家咨询或观看创新战略方案视频进一步了解…

具有可编程电流限制的1.5A电源开关LPW5210用于5V或USB供电输出过流保护只要3毛

前言 适合要求反应时间较快的保护电路&#xff0c;保险丝或自恢复保险丝也能起到保护作用&#xff0c;但断开电流是额定电流的一倍&#xff0c;过流较小时&#xff0c;甚至需要数秒或更长的时间才能保护&#xff0c;因此半导体的过流保护开关更合适&#xff0c;相对成本要高一…

ABC318-E

挺有意思的一题&#xff0c;就当积累一下吧。 做法 枚举i和k会超时&#xff0c;那就只枚举j。 #include<bits/stdc.h> using namespace std; int n; int a[300010]; vector<int> v[300010]; int main(){ scanf("%d",&n); map<int,int&…