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

一、基本思想

归并排序(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.mfbz.cn/a/782207.html

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

相关文章

手把手搭建微信机器人,帮你雇一个24小时在线的个人 AI 助理(上)

上一篇&#xff0c;带领大家薅了一台腾讯云服务器&#xff1a;玩转云服务&#xff1a;手把手带你薅一台腾讯云服务器&#xff0c;公网 IP。 基于这台服务器&#xff0c;今天我们一起动手捏一个基于 LLM 的微信机器人。 0. 前置准备 除了自己常用的微信账号以外&#xff0c;还…

Python之numpy常用知识点总结

文章目录 前言知识点1&#xff1a;np.maximum知识点2&#xff1a;ndarray数据类型知识点3&#xff1a;数据运算知识点4&#xff1a;数组和标量间的运算知识点5&#xff1a;数组的索引和切片知识点6&#xff1a;数组的转置和轴对称知识点7&#xff1a;检索数组元素 前言 在机器学…

【应急响应】Windows应急响应 - 基础命令篇

前言 在如今的数字化时代&#xff0c;Windows系统面对着越来越复杂的网络威胁和安全挑战。本文将深入探讨在Windows环境下的实战应急响应策略。我们将重点关注实际应急响应流程、关键工具的应用&#xff0c;以及如何快速准确地识别和应对安全事件。通过分享实际案例分析&#…

基于S32K144驱动NSD8381

文章目录 1.前言2.芯片介绍2.1 芯片简介2.2 硬件特性2.3 软件特性 3.测试环境3.1 工具3.2 架构 4.软件驱动4.1 SPI4.2 CTRL引脚4.3 寄存器4.4 双极性步进电机驱动流程 5.测试情况6.参考资料 1.前言 最近有些做电磁阀和调光大灯的客户需要寻找国产的双极性步进电机驱动&#xf…

QT入门笔记-自定义控件封装 30

具体代码如下: QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c17# You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES QT_DISABLE_DEPRECATED_BEFORE0x060000 …

Spring AOP源码篇四之 数据库事务

了解了Spring AOP执行过程&#xff0c;再看Spring事务源码其实非常简单。 首先从简单使用开始, 演示Spring事务使用过程 Xml配置&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema…

软件架构之数据库系统(2)

软件架构之数据库系统&#xff08;2&#xff09; 3.4 事务管理3.4.1 并发控制3.4.2 故障与恢复 3.5 备份与恢复3.6分布式数据库系统3.6.1分布式数据库的概念3.6.2 分布式数据库的架构 3.7 数据仓库3.7.1 数据仓库的概念3.7.2数据仓库的结构3.7.3 数据仓库的实现方法 3.8 数据挖…

超高精电容传感器PCAP01调试+LABVIEW数据可视化调试手记

PCAP01超高精电容传感芯片STM32LabView可视化 文章目录 PCAP01超高精电容传感芯片STM32LabView可视化一、PCAP01介绍1.1、PCAP01引脚定义1.2、电容测量1.3、温度测量1.4、PCAP典型测试电路 二、PCAP01的STM32驱动2.1、SPI协议配置2.2、PCAP01浮空电容测量内部温度测量操作流程 …

计算机系统简述

目标 计算机世界并非如此神秘。相反&#xff0c;计算机是非常“确定”的一个系统&#xff0c;即在任何时候&#xff0c;在相同的方法、相同的状态下&#xff08;当然还包括相同的起始条件&#xff09;&#xff0c;同样的问题必然获得相同的结果。其实&#xff0c;计算机并不是…

前端实现无缝自动滚动动画

1. 前言: 前端使用HTMLCSS实现一个无缝滚动的列表效果 示例图: 2. 源码 html部分源码: <!--* Author: wangZhiyu <w3209605851163.com>* Date: 2024-07-05 23:33:20* LastEditTime: 2024-07-05 23:49:09* LastEditors: wangZhiyu <w3209605851163.com>* File…

强化学习的数学原理:时序差分算法

概述 之前第五次课时学习的 蒙特卡洛 的方法是全课程当中第一次介绍的第一种 model-free 的方法&#xff0c;而本次课的 Temporal-Difference Learning 简称 TD learning &#xff08;时序差分算法&#xff09;就是第二种 model-free 的方法。而对于 蒙特卡洛方法其是一种 non…

使用大漠插件进行京东联盟转链

由于之前开发了一套使用api转链的接口在前面几个月失效了。因为京东联盟系统升级&#xff0c;导致之前可以转的链接现在必须要升级权限才可以。但是升级条件对于我们这些自己买东西转链想省点钱的人来说基本上达不到。 所以&#xff0c;基于这种情况。我之前研究过大漠插件&am…

数据库的学习(4)

一、题目 1、创建数据表qrade: CREATE TABLE grade(id INT NOT NULL,sex CHAR(1),firstname VARCHAR(20)NOT NULL,lastname VARCHAR(20)NOT NULL,english FLOAT,math FLOAT,chinese FLOAT ); 2、向数据表grade中插入几条数据: (3,mAllenwiiliam,88.0,92.0 95.0), (4,m,George&…

第七篇——攻谋篇:兵法第一原则——兵力原则,以多胜少

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 微观层面上&#xff0c;也有很多值得深度思考的问题 二、思路&方案 …

用ThreadLocal解决线程隔离问题

存在的以下代码所示的线程隔离问题&#xff1a; package study.用ThreadLocal解决线程隔离问题;/*线程隔离 - 在多线程并发场景下&#xff0c;每个线程的变量都应该是相互独立的线程A&#xff1a;设置&#xff08;变量1&#xff09; 获取&#xff08;变量1&#xff09;线程B&a…

瑞芯微rk356x TF卡烧写选择指定的屏幕打印烧写的过程

rk356x中TF卡烧写屏幕选择 1、开发环境2、问题描述3、解决办法4、总结5、 图片展示1、开发环境 系统:linux系统 芯片:356x 显示:多屏显示(HDMI, MIPI, LVDS, EDP) 2、问题描述 由于在多屏显示的情况下,HDMI屏在LVDS、MIPI或者EDP协同下,默认情况下,在TF卡烧录过程中…

论文润色最强最实用ChatGPT提示词指令

大家好&#xff0c;感谢关注。我是七哥&#xff0c;一个在高校里不务正业&#xff0c;折腾学术科研AI实操的学术人。关于使用ChatGPT等AI学术科研的相关问题可以和作者七哥&#xff08;yida985&#xff09;交流&#xff0c;多多交流&#xff0c;相互成就&#xff0c;共同进步&a…

C++语言相关的常见面试题目(二)

1.vector底层实现原理 以下是 std::vector 的一般底层实现原理&#xff1a; 内存分配&#xff1a;当创建一个 std::vector 对象时&#xff0c;会分配一块初始大小的连续内存空间来存储元素。这个大小通常会随着 push_back() 操作而动态增加。 容量和大小&#xff1a;std::vec…

【Linux】进程间的通信----管道

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

妈妈带女儿美在心里

在这个充满温情与惊喜的午后&#xff0c;阳光温柔地洒落在每一个角落&#xff0c;仿佛连空气弥漫着幸福的味道。就在这样一个平凡的时刻&#xff0c;一段关于爱与成长的温馨画面&#xff0c;悄然在网络上绽放&#xff0c;引爆了无数人的心弦——#奚梦瑶2岁女儿身高#&#xff0c…