归并排序递归与非递归

news2025/1/22 16:45:21

基本思想

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

0f1d3fcc5e85076ed0445cba68d5cb7c.png

 归并排序其实就是等分分割数组,直到分割后的数组有序再将这分割的两个数组归并到一个新的数组里,再拷贝到原数组中。这里就与二叉树的后序遍历极为相似,分割的数组只有一个数时就默认有序了,再合并之后一步步的递归回去。 

代码(递归)

void _MergeSort(int* arr, int left, int right,int* tmp)
{
	if (left == right)//不可能分割出不存在的区间
		return;
	int midi = (left + right) / 2;
	_MergeSort(arr, left, midi, tmp);//分割归并左部分
	_MergeSort(arr, midi + 1, right, tmp);//分割归并右部分

	//归并(begin1和end2之间的数)即left和right之间的数
	int i = 0;//临时数组下标
	int begin1 = left, end1 = midi;
	int begin2 = midi + 1, end2 = right;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (arr[begin1] < arr[begin2])
			tmp[i++] = arr[begin1++];
		else
			tmp[i++] = arr[begin2++];
	}
	while (begin1 <= end1)
	{
		tmp[i++] = arr[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = arr[begin2++];
	}

	memcpy(arr+left, tmp, sizeof(int) * i);//归并一次就拷贝一次

}
void MergeSort(int* arr, int left, int right)
{
	int* tmp = (int*)malloc(sizeof(int*) * (right + 1));
	_MergeSort(arr, 0, right,tmp);
	free(tmp);
}

代码1(非递归)

void _MergeSort(int* arr, int left, int right, int* tmp)
{

	int gap = 1;//每一组的数据个数
	while (gap < right)
	{
		
		for (int i = 0; i <= right; i += 2 * gap)//两两归并,遍历整个数组
		{
			int j = 0;//临时数组的下标
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;

			if (end1 > right || begin2 > right)
				break;
			if (end2 > right)
			{
				end2 = right;
			}

			while (begin1 <= end1 && begin2 <= end2)
			{
				if (arr[begin1] < arr[begin2])
					tmp[j++] = arr[begin1++];
				else
					tmp[j++] = arr[begin2++];
			}
			while (begin1 <= end1)
			{
				tmp[j++] = arr[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = arr[begin2++];
			}
			memcpy(arr + i, tmp, sizeof(int) * j);//归并一次拷贝一次
		}
		gap *= 2;
	}

}

非递归就要知道该代码原来递归是怎么走的,递归的部分实际上是在一直分割成两部分,直到不能再分割了以后,就开始合并到tmp临时数组里,所以非递归的写法实际就也是分组执行,先是单个数是一组,两两一组进行比较拷贝,原先拷贝好的就可以是一组了,此时每组就有两个数是有序的,再两两一组,两组再进行拷贝,此时拷贝好的一组就有四个有序的数了,再进行四四一组.......

但是这可能存在越界的情况,两组数据拷贝,极有可能就越界,而且存在三种越界的情况:

5eab0d1a341845ad83c158eeff837332.png

 而上面的一二两种情况又可以看作一种:多余了已经有序的一组(不到一组)此时该组已经有序了,所以也不用进行归并了,直接放在原数组中就行了,但是你memcpy拷贝数组就得一组组的拷贝了,不能归并完整个数组以后再全部拷贝到原数组。

而第三种情况就是多了不仅仅一组的数据但是却又不够两组,此时就不能说这一组半是有序的,所以就重行划区间,end2就指向最后一个数的下标,将这半组也看成一组,两两拷贝数据成有序。

代码2(非递归) 

void _MergeSort(int* arr, int left, int right, int* tmp)
{
	int gap = 1;//每一组的数据个数
	while (gap < right)
	{
		int j = 0;//临时数组下标
		for (int i = 0; i <= right; i += 2 * gap)//两两归并整个数组
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			if (end1 > right)
			{
				end1 = right;
				begin2 = end2 + 1;//不存在的区间
			}
			else if(begin2 > right)
			{
				begin2 = end2 + 1;//不存在的区间
			}
			else if (end2 > right)
			{
				end2 = right;
			}
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (arr[begin1] < arr[begin2])
					tmp[j++] = arr[begin1++];
				else
					tmp[j++] = arr[begin2++];
			}
			while (begin1 <= end1)
			{
				tmp[j++] = arr[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = arr[begin2++];
			}
		}
		memcpy(arr, tmp, sizeof(int) * j);//一次拷贝整个数组数据
		gap *= 2;
	}

}

这就是可以一次拷贝整个数组的情况,即当遇到越界的情况就就调整范围,继续拷贝。

0beea402e2354a38b54fa0cf27fc5fae.jpeg

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

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

相关文章

Jenkins (二)

Jenkins (二) 使用pipeline script 简单编译 发布war工程到远程tomcat中 配置所需 下载 apache-maven-3.9.3.tar.gz 解压 apache-maven-3.9.3-bin.tar.gz 拷贝到 docker jenkins 镜像里 $ docker cp apache-maven-3.9.3 37259c708ca1:/home/下载apache-tomcat-8.5.91.tar.gz …

压测工具之JMeter使用

文章目录 前言压测工具如何使用启动JMeter工具开始创建测试环境1、创建线程组2、配置元件3、构造HTTP请求4、添加HTTP请求头信息 5、添加断言6、添加查看结果树7、添加聚合报告信息8、测试计划创建完成了 执行测试计划 前言 最近公司项目需要进行压测&#xff0c;查验S A A S …

7.18训练总结

考场错误&#xff1a; 今天是一套neerc的题&#xff0c;难度相对较大&#xff0c;我犯的低级错误比较少&#xff0c;但是对于题目顺序的把握能力&#xff0c;应该提高&#xff0c;尝试去做自己擅长的题目&#xff0c;而不是跟着别人的开题顺序&#xff0c;这样能够更顺畅吧。 …

实验室LIMS系统检测工作流程

LIMS系统检测工作流程 检测工作流程是LIMS核心内容&#xff0c;通过检测工作管理可加强协同工作能力、进一步强化质量控制环节、提高数据报出速度&#xff0c;提高工作效率、减低数据出错率&#xff0c;保证质量记录的完整、监控规范的执行&#xff1b;检测流程以样品检测为主…

Jenkins | 获取凭证密码

目录 方法一&#xff1a;查看所有账号及密码 方法二&#xff1a;查看指定账号密码 方法一&#xff1a;查看所有账号及密码 Jenkins > 系统管理 > 脚本命令行 com.cloudbees.plugins.credentials.SystemCredentialsProvider.getInstance().getCredentials().forEach{i…

element-ui message消息提示组件 ①延长提示消息在页面停留时间②提示消息换行

以实现下面的效果为示例 完整代码&#xff1a; let msgList ["数据1被引用", "数据2被引用"];// 使用html的换行标签拼接信息&#xff0c;默认行距太小&#xff0c;此处用两个<br/><br/>let message 以下数据不能删除&#xff0c;原因是&…

【Spring core学习四】Bean作用域和生命周期

目录 一、Bean的作用域 &#x1f308;1、被修改的Bean值现象 &#x1f308;2、 Bean 的 6 种作⽤域 &#x1f308;3、设置作用域 二、Spring的执行流程 三、Bean的生命周期 &#x1f308;1、Bean生命周期的过程 &#x1f308;2、演示生命周期 一、Bean的作用域 &…

[MySql]JDBC编程

JDBC&#xff0c;即Java Database Connectivity&#xff0c;java数据库连接。是一种用于执行SQL语句的Java API&#xff0c;它是Java中的数据库连接规范。这个API由 java.sql.*,javax.sql.* 包中的一些类和接口组成&#xff0c;它为Java开发人员操作数据库提供了一个标准的API&…

全域Serverless化,华为云引领下一代云计算新范式

近日&#xff0c;华为开发者大会2023&#xff08;Cloud&#xff09;在东莞成功举办&#xff0c;期间“全域Serverless化&#xff0c;引领下一代云计算新范式”专题论坛人气满满。华为云首席产品官方国伟携手业界专家、客户、伙伴&#xff0c;面向广大开发者&#xff0c;分享了在…

Authing 身份云上线数据对象管理(元数据),助力企业构建唯一身份源

在身份管理领域&#xff0c;元数据具有重要的作用和价值。元数据有助于理解数据的结构和意义&#xff0c;提升数据处理效率&#xff1b;促进跨部门、跨组织的数据共享和协作&#xff1b;以及支持数据分析&#xff0c;为业务决策提供支持等。当前&#xff0c;Authing 身份云已经…

在ICC/ICC2/FC中运行Calibre

1. which calibre找到calibre的安装目录 > which calibre > /eda/mentor/ixl_cal_version/bin/calibre 2. 在 /eda/mentor/ixl_cal_version目录下使用find ./* -name "icc_calibre.tcl",找到icc_calibre.tcl 3. 打开icc_calibre.tcl里面有不同工具(ICC2/FC/…

《Linux0.11源码解读》理解(五) head之开启分页

先回顾一下地址长度以及组合的演变&#xff1a;16位cpu意味着其数据总线/寄存器也是16位&#xff0c;但是地址总线&#xff08;寻址能力&#xff09;与此无关&#xff0c;可能是20位。可以参考&#xff1a;cpu的位宽、操作系统的位宽和寻址能力的关系_cpu位宽_brahmsjiang的博客…

C++——map和set(multimap和multiset)

目录 1.关联式容器 2.键值对 3.树形结构的关联式容器 3.1 set 3.1.1 set的介绍 3.1.2 set的使用 3.2 multiset 3.2.1 multiset的介绍 3.2.2 multiset的使用 3.3 map 3.3.1 map的介绍 3.3.2 map的使用 3.4 multimap 3.4.1 multimap的介绍 3.4.2 multimap的使用 …

抖音小店选品攻略:10个技巧助你选择助轻松学会选品技巧

抖音小店是目前非常火爆的电商平台之一&#xff0c;许多商家都希望能在抖音上开设自己的小店。而在开设抖音小店之前&#xff0c;选品是一个非常重要的环节。下面是不若与众总结的一些抖音小店选品技巧&#xff0c;希望能帮助到你。 1. 确定目标受众&#xff1a;在选品之前&…

数据库应用:MySQL高级语句

目录 一、理论 1.常用查询 2.函数 3.进阶查询 二、实验 1.普通查询 2.函数 3.进阶查询 三、问题 1.MySQL || 运算符不生效 四、总结 一、理论 1.常用查询 常用查询包括&#xff1a;增、删、改、查&#xff1b; 对 MySQL 数据库的查询&#xff0c;除了基本的查询外…

(学习笔记-TCP连接断开)建立了连接,但是客户端或服务端出现问题,会怎么样?

客户端突然出现故障 客户端出现故障指的是客户端的主机发生了宕机或者断电的场景。发生这种情况的时候&#xff0c;如果服务端一直不会发送数据给客户端&#xff0c;那么服务端是永远无法感知到客户端宕机这件事的&#xff0c;也就是服务端的TCP连接将一直处于ESTABLISH 状态&…

两巨头强强联手!美国EB-5投资移民新项目侨外出国首发

7月15日&#xff0c;在侨外出国“见证辉煌历史 重启明日新章”的主题活动中&#xff0c;一个全新乡村EB-5投资移民项目——峰堡长岭天然气开发项目正式扬帆起航。 这一项目&#xff0c;由两大行业巨头——侨外出国和CanAm基金强强联手。众所周知&#xff0c;侨外出国是EB-5投资…

并发编程中常见的锁策略

本文介绍一些常见的锁策略。 锁策略是多线程编程中相对进阶的内容&#xff0c;它不仅仅局限于Java&#xff0c;任何和“锁”相关的话题&#xff0c;都可能会涉及到这些内容&#xff1b;即使是别的语言&#xff0c;只要涉及到“锁”&#xff0c;也都会涉及到锁策略。 锁策略的…

px4上传数据waiting for bootloader

输入make px4_fmu-v6c_default upload&#xff0c;出现waiting for bootloader 原因&#xff0c;可能是启动了QGC占用了端口&#xff0c;把QGC关掉&#xff0c;重新上电&#xff0c;就OK了。

C++ 继承与多态的基本用法

目录 1.继承 1.1访问等级 1.2函数遮蔽 2.多态 2.1虚函数 1.继承 有父类&#xff0c;有子类&#xff0c;这种层次关系就叫继承&#xff0c;也就说说子类能从父类哪里继承很多东西&#xff0c;继承这种概念或性质是面向对象程序设计的核心思想之一。 这种继承需要先定义一个父…