【排序算法】 归并排序详解!深入理解!思想+实现!

在这里插入图片描述

🎥 屿小夏 : 个人主页
🔥个人专栏 : 算法—排序篇
🌄 莫道桑榆晚,为霞尚满天!

文章目录

  • 📑前言
  • 🌤️归并排序的思想
    • ☁️基本思想
    • ☁️归并的思想实现
    • ☁️分治法
  • 🌤️归并排序的实现
    • ☁️核心操作步骤
    • ☁️递归版归并实现
      • ⭐代码实现详解:
    • ☁️非递归版归并实现
      • ⭐代码实现详解:
  • 🌤️归并排序特性总结
  • 🌤️全篇总结

📑前言

​ 什么是归并?通过归并排序就能让数据有序?分治法是怎么在归并排序上应用的?本文将对归并排序进行细致入微的讲解,庖丁解牛般让你彻底明白归并排序!

🌤️归并排序的思想

☁️基本思想

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

☁️归并的思想实现

​ 将两个有序数组合并成一个有序数组的操作。在归并排序中,通过不断地将数组分成两半,分别对每一半进行排序,然后将排好序的两个子数组合并成一个有序数组,最终得到整个数组有序的结果。

☁️分治法

​ 分治法在归并排序中的应用是将问题分解成更小的子问题,然后分别解决这些子问题,最后将子问题的解合并起来得到原问题的解。具体来说,归并排序的分治法应用如下:

  1. 分解:将待排序的数组分成两个子数组,分别为左子数组和右子数组。
  2. 解决:递归地对左子数组和右子数组进行归并排序。
  3. 合并:将排好序的左子数组和右子数组合并成一个有序数组。

🌤️归并排序的实现

☁️核心操作步骤

静图全步骤概览:

在这里插入图片描述

动图一步步的逻辑实现:

在这里插入图片描述

☁️递归版归并实现

//归并
void _MergeSort(int* a, int* tmp, int begin, int end)
{
	if (end <= begin)
	{
		return;
	}
	int mid = (begin + end) / 2;
	_MergeSort(a, tmp, begin, mid);
	_MergeSort(a, tmp, mid + 1, end);
	// a->[begin, mid][mid+1, end]->tmp
	//归并
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	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));
}
//归并(递归版)
void MergeSort(int* a, int n)
{
	int* tmp = malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	_MergeSort(a, tmp, 0, n - 1);
	free(tmp);
}

​ 归并需要开一个同样大的tmp数组来存放数据,相当于是拿空间来换时间了.

⭐代码实现详解:

  1. 首先,将整个序列分为两部分,分别递归调用_MergeSort函数对左右两部分进行排序。
  2. 在_MergeSort函数中,首先判断递归终止条件,如果end小于等于begin,则表示当前子序列只有一个元素或者为空,无需排序,直接返回。
  3. 然后,计算中间位置mid,并分别递归调用_MergeSort函数对左右两部分进行排序。
  4. 接下来,进行归并操作。首先,设置四个指针begin1、end1、begin2、end2分别指向左右两部分的起始和结束位置,以及一个指针index指向当前归并结果的位置。
  5. 然后,使用两个循环比较左右两部分的元素大小,并将较小的元素放入tmp数组中,同时移动相应的指针。
  6. 最后,将剩余的元素复制到tmp数组中。
  7. 最后,将tmp数组中的元素复制回原数组a中,完成归并排序。

☁️非递归版归并实现

​ 非递归版是在递归上进行了修改,将其递归改为了循环。

//归并(非递归版)
void _MergeSortNotR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	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;
			}

			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+1) * sizeof(int));
		}
		gap *= 2;
	}
	free(tmp);
}

⭐代码实现详解:

  1. 分配一个临时数组tmp,用于存储归并结果。

  2. 设置一个变量gap为1,表示归并的间隔大小。

  3. 接下来,循环执行以下操作,直到gap大于等于n:

    1. 遍历整个数组,每次取两个相邻的子序列进行归并。
    2. 计算左右两个子序列的起始和结束位置。
    3. 判断右子序列的结束位置是否超过了数组的长度,如果超过,则将结束位置设置为数组的最后一个元素的下标。
    4. 使用两个指针begin1和begin2分别指向左右两个子序列的起始位置,使用指针end1和end2分别指向左右两个子序列的结束位置。
    5. 使用一个指针index指向当前归并结果的位置。
    6. 使用一个循环,比较左右两个子序列的元素大小,并将较小的元素放入临时数组tmp中,同时移动相应的指针。
    7. 如果左子序列还有剩余元素,则将剩余元素复制到tmp数组中。
    8. 如果右子序列还有剩余元素,则将剩余元素复制到tmp数组中。
    9. 将tmp数组中的元素复制回原数组a中。
    10. 将gap乘以2,进行下一轮归并。
  4. 最后,释放临时数组tmp的内存空间。

🌤️归并排序特性总结

  1. 稳定性:归并排序是一种稳定的排序算法,即相等元素的相对顺序在排序后不会改变。
  2. 时间复杂度:归并排序的时间复杂度是O(nlogn),其中n是待排序序列的长度。这是由于归并排序的核心操作是将序列分成两个子序列,然后分别进行排序,再将排序好的子序列合并,而分割和合并操作都需要O(logn)的时间,所以总的时间复杂度是O(nlogn)。
  3. 空间复杂度:归并排序的空间复杂度是O(n),其中n是待排序序列的长度。这是由于归并排序需要一个与待排序序列相同大小的额外空间来存储临时的合并结果。
  4. 非原地排序:归并排序不是原地排序算法,即它需要额外的空间来存储临时的合并结果。这是因为在合并操作中,需要同时访问两个子序列的元素,并将它们按照顺序合并到一个新的序列中。
  5. 递归实现:归并排序通常使用递归的方式来实现,即将待排序序列不断分割成更小的子序列,直到子序列的长度为1,然后再将这些子序列按照顺序合并成一个有序的序列。递归实现的归并排序代码简洁易懂,但是由于递归调用的开销比较大,所以在实际应用中可能会使用迭代的方式来实现归并排序。
  6. 适用性:归并排序适用于各种数据规模的排序,而且对于大规模数据的排序效果较好。它的时间复杂度稳定在O(nlogn),不会因为数据规模的增大而导致时间复杂度的增加。此外,归并排序还适用于外部排序,即对于无法一次性加载到内存的大规模数据进行排序。

🌤️全篇总结

​ 经过对归并排序的思想,特性,代码实现这些细致入微的讲解,相信聪明的你肯定已经学会了叭😊😊!

☁️ 好了,由于篇幅有限,本章只是对归并进行了深度解刨,后序会出更多的排序算法哦!
看到这里希望给博主留个:👍点赞🌟收藏⭐️关注!
你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦!
在这里插入图片描述

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

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

相关文章

java 版本企业招标投标管理系统源码+多个行业+tbms+及时准确+全程电子化

项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及审…

一文彻底理解python浅拷贝和深拷贝

目录 一、必备知识二、基本概念三、列表&#xff0c;元组&#xff0c;集合&#xff0c;字符串&#xff0c;字典浅拷贝3.1 列表3.2 元组3.3 集合3.4 字符串3.5 字典3.6 特别注意可视化展示浅拷贝总结 四、列表&#xff0c;元组&#xff0c;集合&#xff0c;字符串&#xff0c;字…

Python+Robotframework实现http接口自动化测试详解

前言 下周即将展开一个http接口测试的需求&#xff0c;刚刚完成的java类接口测试工作中&#xff0c;由于之前犯懒&#xff0c;没有提前搭建好自动化回归测试框架&#xff0c;以至于后期rd每修改一个bug&#xff0c;经常导致之前没有问题的case又产生了bug&#xff0c;所以需要…

LED数码管的静态显示与动态显示(Keil+Proteus)

前言 就是今天看了一下书上的单片机实验&#xff0c;发现很多的器件在Proteus中都不知道怎么去查找&#xff0c;然后想做一下这个实验&#xff0c;尝试能不能实现&#xff0c;LED数码管的两个还可以实现&#xff0c;但是用LED点阵显示器的时候他那个网络标号不知道是什么情况&…

openGauss学习笔记-111 openGauss 数据库管理-管理用户及权限-用户权限设置

文章目录 openGauss学习笔记-111 openGauss 数据库管理-管理用户及权限-用户权限设置111.1 给用户直接授予某对象的权限111.2 给用户指定角色111.3 回收用户权限 openGauss学习笔记-111 openGauss 数据库管理-管理用户及权限-用户权限设置 111.1 给用户直接授予某对象的权限 …

【uniapp】uniapp实现input输入显示数字键盘:

文章目录 一、官网文档&#xff1a;二、文档&#xff1a;三、效果&#xff1a;【1】number&#xff1a;iPhone原生数字键盘不显示小数点【2】digit&#xff1a;【3】digit和inputmode&#xff1a; 一、官网文档&#xff1a; input | uni-app官网 二、文档&#xff1a; 三、效果…

正点原子嵌入式linux驱动开发——Linux 多点电容触摸屏

随着智能手机的发展&#xff0c;电容触摸屏也得到了飞速的发展。相比电阻触摸屏&#xff0c;电容触摸屏有很多的优势&#xff0c;比如支持多点触控、不需要按压&#xff0c;只需要轻轻触摸就有反应。ALIENTEK的三款RGB LCD屏幕都支持多点电容触摸&#xff0c;本章就以ATK7016这…

git命令清单

一、设置和配置 1.初始化一个新的仓库&#xff1a; git init2.克隆&#xff08;Clone&#xff09;一个远程仓库到本地&#xff1a; git clone <repository_url>3.配置用户信息&#xff1a; git config --global user.name "Your Name" git config --global…

matlibplot绘图设置标签角度

如下图所示&#xff0c;当我们绘图的时候有时候会遇到标注太长显示不全&#xff0c;这时候需要修改标注的角度来实现&#xff1a; **plt.xticks(rotation70)**设置x轴旋转70度 import matplotlib.pyplot as plt import numpy as np CHN[13.6081.06**i for i in range(1,31)] U…

C语言数组首地址学习1

C语言数组名也是数组首地址&#xff1b;数组首地址&#xff0c;也就是数组首元素地址&#xff1b; 数组首地址也可以用第0个元素加&表示&#xff0c;数值a的首地址是&a[0]&#xff1b; #include <stdio.h> int main(){int nums[5];int i;//从控制台读取用户输…

第20期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练 Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…

安防视频监控平台EasyCVR前端解码与后端解码的区别介绍

视频监控平台/视频存储/视频分析平台EasyCVR基于云边端一体化管理&#xff0c;支持多类型设备、多协议方式接入&#xff0c;具体包括&#xff1a;国标GB28181协议、RTMP、RTSP/Onvif、海康Ehome&#xff0c;以及海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石SDK等&#x…

基于英伟达NVIDIA Jetson Xavier nx的Ubuntu系统安装nginx,mysql, java8

记录一下基于英伟达NVIDIA Jetson Xavier nx的Ubuntu系统安装nginx&#xff0c;mysql&#xff0c; java8(非docker方式) nx系统主要用于开发ai边缘人工智能视觉计算&#xff0c;人脸识别&#xff0c;车辆识别等&#xff0c;同样的也可以部署一些常见的程序应用 nx系统界面 …

SQL注入——二次注入漏洞

文章目录 SQL注入——二次注入漏洞1. 二次注入原理2. 二次注入需要具备的两个条件3. 二次注入实例4. 总结 SQL注入——二次注入漏洞 1. 二次注入原理 在第一次插入恶意数据的时候&#xff0c;只是对其中的特殊字符进行了转义&#xff0c;在写入数据库的时候还是原来的字符&am…

分类预测 | Matlab实现KOA-CNN-GRU-selfAttention多特征分类预测(自注意力机制)

分类预测 | Matlab实现KOA-CNN-GRU-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09; 目录 分类预测 | Matlab实现KOA-CNN-GRU-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09;分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matla…

一文吃透低代码开发与传统IT开发的区别

目录 一、含义不同 二、开发门槛不同 三、两者之间的区别 1、从技术特征来看 2、从目标开发者来看 四、低代码平台使用感受&#xff1f; &#xff08;1&#xff09;自定义模块&#xff0c;满足不同的业务需求 &#xff08;2&#xff09;工作流引擎&#xff0c;简化复杂流程的管…

c++-set和map

文章目录 前言一、set容器1、set容器介绍2、set的使用2.1 set的构造函数和迭代器2.2 set的容量2.3 set修改操作 3、multiset容器3.1 multiset容器介绍3.2 multiset容器使用 二、map容器1、map容器介绍2、map容器使用2.1 map的构造函数与迭代器2.2 map中元素的修改2.3 map的容量…

ChatGPT 3.5只有200亿规模的参数?最新微软的论文暴漏OpenAI的ChatGPT的参数规模远低于1750亿!

本文来自DataLearnerAI官方网站&#xff1a;ChatGPT 3.5只有200亿规模的参数&#xff1f;最新微软的论文暴漏OpenAI的ChatGPT的参数规模远低于1750亿&#xff01; | 数据学习者官方网站(Datalearner)https://www.datalearner.com/blog/1051698672594665 2022年11月底发布的Cha…

数据库的事务四大特性(ACID)、详解隔离性以及隔离级别、锁

文章目录 &#x1f389;数据库的事务四大特性&#xff08;ACID&#xff09;以及隔离性一、事务的四大特性✨1、原子性&#xff08;Atomicity&#xff09;&#x1f38a;2、一致性&#xff08;Consistency&#xff09;&#x1f38a;3、隔离性&#xff08;Isolation&#xff09;&a…

TensorFlow案例学习:简单的音频识别

前言 以下内容均来源于官方教程&#xff1a;简单的音频识别&#xff1a;识别关键字 音频识别 下载数据集 下载地址&#xff1a;http://storage.googleapis.com/download.tensorflow.org/data/mini_speech_commands.zip 可以直接浏览器访问下载。 下载完成后将其解压到项目…