排序 -- 手撕归并排序(递归和非递归写法)

news2024/11/15 3:28:21

一、基本思想

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

 二、归并排序的特性总结

1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(N)
4. 稳定性:稳定

三、归并排序

1、递归实现

1.1 实现思想

使用递归方法来实现归并排序,这其中不止包含了递归这个思想,还使用了分治的理念。

其原理就是把待排序数组分成两个子序列,再分别把两个子序列分成其对应的子序列,直到每个子序列都只有唯一的一个数据时就停止递归。然后分别对子序列进行排序,最后将排序好的子序列合并起来。

一个小tip:就是归并排序归并数据的过程中我们需要额外开辟一个空间来存放中间数据,如果在原数组中进行归并的话会造成数据的覆盖或者导致数据错乱!!!

1.2 具体实现

// 时间复杂度O(N*logN)  空间复杂度:O(N)
void _MergeSort(int* a, int* tmp, int begin, int end)
{
	if (end <= begin)
	{
		return;
	}

	int mid = (begin + end) / 2;
	// [begin, mid][mid+1, end]
	_MergeSort(a, tmp, begin, mid);
	_MergeSort(a, tmp, mid + 1, end);

	// 归并到tmp数据组,再拷贝回去
	// a->[begin, mid][mid+1, end]->tmp
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;

	//尾插tmp数组下标
	int index = begin;

	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++];
	}

	//拷贝回原数组
	memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int)); //+begin是因为归并的数组下标不一定从0开始
}

//归并排序
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int)*n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}

	_MergeSort(a, tmp, 0, n - 1);

	free(tmp);
}

 2、 非递归实现

2.1 实现思想

相较于递归实现,非递归实现采用与希尔排序相似的方法。就是使用gap来确定归并区间并进行归并

 2.2 具体实现

//非递归--归并排序(防止下标越界)
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, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;


			// 如果第二组不存在,这一组不用归并了
			if (begin2 >= n)
			{
				break;
			}

			// 如果第二组的右边界越界,修正一下
			if (end2 >= n)
			{
				end2 = n - 1;
			}

			// [begin1,end1] [begin2,end2] 归并
			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++];
			}

			// 拷贝回原数组
			memcpy(a + i, tmp + i, (end2 - i) * sizeof(int));
		}
		gap *= 2;
	}

	free(tmp);
}

2.3 关于非递归实现归并排序的一些细节

 在我们要用非递归来实现归并排序时需要注意的是用gap来确定归并区间的界限会不会造成数组越界的问题。

上面这张图是我们用gap来区分归并的区间,这种方法有可能会造成第二个数组全部越界或者第二个数组的end越界。但我们要注意的是第一个数组的开头begin1永远不可能越界,因为begin1 == i,而循环条件中 i < n

如下图所示:

所以我们就只需要加两个判定条件即可

1、判断begin2是否 >= 数组长度n,如果大于等于就直接跳出循环不用再进行归并

2、判断end2是否 >= 数组长度n,如果大于等于就修正end2,使其 == 数组结束位置 n - 1

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

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

相关文章

掌上教务系统-计算机毕业设计源码84604

摘要 在数字化教育日益成为主流的今天&#xff0c;教务管理系统的智能化和便捷性显得尤为重要。为满足学校、教师、学生及家长对教务管理的高效需求&#xff0c;我们基于Spring Boot框架设计并实现了一款掌上教务系统。该系统不仅具备课程分类管理功能&#xff0c;使各类课程信…

软件架构之开发方法

软件架构之开发方法 第6章&#xff1a;开发方法6.1 软件生命周期6.2 软件开发模型6.2.1 瀑布模型6.2.2 演化模型6.2.3 螺旋模型6.2.4 增量模型6.2.5 构件组装模型 6.3 统一过程6.4 敏捷方法6.4.1 极限编程6.4.2 特征驱动开发6.4.3 Scrum6.4.4 水晶方法6.4.5 其他敏捷方法 6.5 软…

《梦醒蝶飞:释放Excel函数与公式的力量》9.5 IRR函数

9.5 IRR函数 IRR函数是Excel中用于计算内部收益率&#xff08;Internal Rate of Return, IRR&#xff09;的函数。内部收益率是评估投资项目盈利性的重要指标&#xff0c;它表示使投资项目的净现值&#xff08;NPV&#xff09;为零的折现率。 9.5.1 函数简介 IRR函数通过一系…

微软开源GraphRAG的使用教程-使用自定义数据测试GraphRAG

微软在今年4月份的时候提出了GraphRAG的概念&#xff0c;然后在上周开源了GraphRAG,Github链接见https://github.com/microsoft/graphrag,截止当前&#xff0c;已有6900Star。 安装教程 官方推荐使用Python3.10-3.12版本&#xff0c;我使用Python3.10版本安装时&#xff0c;在…

Java:String 类

文章目录 一、概念二、创建字符串三、字符串长度四、连接字符串五、比较字符串 一、概念 字符串广泛应用 在 Java 编程中&#xff0c;在 Java 中字符串属于对象&#xff0c;Java 提供了 String 类来创建和操作字符串。 二、创建字符串 创建字符串最简单的方式如下: // 直接创…

利用Python进行数据分析PDF下载经典数据分享推荐

本书由Python pandas项目创始人Wes McKinney亲笔撰写&#xff0c;详细介绍利用Python进行操作、处理、清洗和规整数据等方面的具体细节和基本要点。第2版针对Python 3.6进行全面修订和更新&#xff0c;涵盖新版的pandas、NumPy、IPython和Jupyter&#xff0c;并增加大量实际案例…

什么是Common Flash Interface

目录 1. CFI概述 2. CFI的使用小结 3. CFI在车规MCU里有用吗 在看关于ifx的标准flash驱动配置时&#xff0c;无意中瞄到一个注灰的选项&#xff1a; Try to use CFI information to detect Flash Type 之前讲过CFI这个标准&#xff0c;但为何在IFX memtool工具里注灰&#x…

opencv实现人脸检测功能----20240704

opencv实现人脸检测 早在 2017 年 8 月,OpenCV 3.3 正式发布,带来了高度改进的“深度神经网络”(dnn)模块。 该模块支持多种深度学习框架,包括 Caffe、TensorFlow 和 Torch/PyTorch。OpenCV 的官方版本中包含了一个更准确、基于深度学习的人脸检测器, 链接:基于深度学习…

基于springboot+vue+uniapp的贵工程寝室快修小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…

人员定位系统的功能,你知道多少呢?

在此前的文章中&#xff0c;说到了人员定位系统用于化工厂定位这一用途来完善工厂管理&#xff0c;但同时&#xff0c;基于人员定位系统的强大功能&#xff0c;该系统的应用范围也要宽范的多&#xff0c;那么&#xff0c;本篇文章就来为大家介绍一下吧。 人员定位系统的功能简介…

maxwell启动报错:Could not find first log file name in binary log index file

出现该问题是因为&#xff1a;maxwell 读取的是 mysql 的 binlog 日志&#xff0c;而配置文件中的两个值与 binlog 的最新值没有保持一致导致 1. 切换到maxwell的库 show master status;记住图片中的 FIle 和 Position 2. 修改maxwell的配置 SELECT * from positions p ;将…

怎样优化 PostgreSQL 中对 XML 数据的存储和查询?

文章目录 一、数据类型选择二、索引优化三、查询优化四、分区策略五、存储参数调整六、示例代码与解释七、性能测试与监控八、数据清理与压缩九、注意事项 在 PostgreSQL 中处理 XML 数据时&#xff0c;为了实现高效的存储和查询&#xff0c;需要采取一系列的优化策略。以下将详…

国外服务器备案主要需要准备什么

在全球化日益加深的今天&#xff0c;许多企业和个人选择将服务器部署在国外&#xff0c;以享受更广泛的用户覆盖、更低廉的运营成本或更灵活的网络环境。然而&#xff0c;不同国家和地区对服务器备案的要求各不相同&#xff0c;但通常而言&#xff0c;进行国外服务器备案主要需…

轻松集成,高效变现:Flat Ads SDK助力开发者轻松跨越广告变现门槛

在当今的移动应用开发领域,广告变现是开发者们普遍关注的重要话题。如何在不影响用户体验的前提下,最大化地实现广告收益,成为了许多开发者面临的挑战。为此,Flat Ads SDK 应运而生,它以“轻松集成,合规守护,高效变现”为核心理念,帮助开发者轻松解决流量变现难题。 一、高效变…

微信小程序的智慧物流平台-计算机毕业设计源码49796

目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3研究方法 1.4开发技术 1.4.1 微信开发者工具 1.4.2 Node.JS框架 1.4.3 MySQL数据库 1.5论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 用户登录流程 2.2.2 数据删除流程 2.3 系统功能分…

【基础算法总结】分治—归并

分治—归并 1.排序数组2.交易逆序对的总数3.计算右侧小于当前元素的个数4.翻转对 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.排序数组 …

盘点2024年6月Sui生态发展,了解Sui近期成长历程

随着区块链技术的迅猛发展&#xff0c;Sui生态在2024年6月取得了令人欣喜的进步。作为创新的L1协议&#xff0c;Sui不仅在技术革新方面表现突出&#xff0c;还在DeFi、游戏应用和开发者工具等领域展现出强大的潜力。本篇文章将全面盘点Sui在过去一个月内的生态发展&#xff0c;…

vue3+ts 重复参数提取成方法多处调用以及字段无值时不传字段给后端

参数提取前的写法&#xff0c;此写法值为空的时候也会传空字段给后端 会把无值的空字段传给后端 修改后的写法&#xff0c;不会把没有值的字段传给后端 // 列表和导出需要传给后端的公共参数&#xff08;加 || undefined即可过滤空字段&#xff09; const getCurentParam () …

Zabbix 6.0 组件 工作原理和组件

Zabbix组件 C/S架构 服务端&#xff1a;zabbix server&#xff08;端口10051&#xff09;&#xff1a;zabbix服务端进程&#xff0c;用于接收代理端发来的监控指标数据&#xff0c;配置和管理zabbix应用程序&#xff0c;也是监控系统的告警中心&#xff08;通过监控项告警触…

伦敦银交易平台价格的突破成不成功?这点很重要!

在伦敦银交易中&#xff0c;当银价出现突破的时候&#xff0c;也正是引起很多投资者关注的时候。一旦银价出现突破&#xff0c;很可能是新行情的开端。但是做过突破交易&#xff0c;有相关经验的朋友会发现&#xff0c;自己在伦敦银交易平台做突破的时候&#xff0c;也并不是每…