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

这篇具有很好参考价值的文章主要介绍了【排序算法】 归并排序详解!深入理解!思想+实现!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【排序算法】 归并排序详解!深入理解!思想+实现!,算法的奇妙之旅,算法,排序算法,数据结构

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

📑前言

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

🌤️归并排序的思想

☁️基本思想

归并排序(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),不会因为数据规模的增大而导致时间复杂度的增加。此外,归并排序还适用于外部排序,即对于无法一次性加载到内存的大规模数据进行排序。

🌤️全篇总结

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

☁️ 好了,由于篇幅有限,本章只是对归并进行了深度解刨,后序会出更多的排序算法哦!
看到这里希望给博主留个:👍点赞🌟收藏⭐️关注!
你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦!
【排序算法】 归并排序详解!深入理解!思想+实现!,算法的奇妙之旅,算法,排序算法,数据结构文章来源地址https://www.toymoban.com/news/detail-717957.html

到了这里,关于【排序算法】 归并排序详解!深入理解!思想+实现!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [排序算法]:归并排序(Merge Sort)(递归与非递归实现详解)

            归并排序,是创建在归并操作上的一种有效的排序算法。算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。归并排序思路简单,速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。

    2024年01月20日
    浏览(31)
  • 深度理解排序算法——归并排序

    ………………………………………………………………………………… 给定一段无序数组,将数组拆分成 两段 ,使得 左右两段 得数组均呈现有序状态,再借助 临时数组 将两段数组归并至一块呈现有序,最后 拷贝 回原数组即得到有序数组。 从逻辑上理解,就是一颗 二叉

    2024年02月03日
    浏览(27)
  • 【算法系列 | 4】深入解析排序算法之——归并排序

    你只管努力,其他交给时间,时间会证明一切。 文章标记颜色说明: 黄色 :重要标题 红色 :用来标记结论 绿色 :用来标记一级论点 蓝色 :用来标记二级论点 决定开一个算法专栏,希望能帮助大家很好的了解算法。主要深入解析每个算法,从概念到示例。 我们一起努力

    2024年02月08日
    浏览(30)
  • 【排序算法】深入理解快速排序算法:从原理到实现

    目录 1. 引言 2. 快速排序算法原理 3. 快速排序的时间复杂度分析 4. 快速排序的应用场景 5. 快速排序的优缺点分析 5.1 优点: 5.2 缺点: 6. Java、JavaScript 和 Python 实现快速排序算法 6.1 Java 实现: 6.2 JavaScript 实现: 6.3 Python 7. 总结        快速排序是一种经典的排序算法,它的

    2024年03月20日
    浏览(30)
  • C语言实现八大排序算法(详解插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序(递归和非递归)、归并排序(递归和非递归)和计数排序)

    本篇文章使用C语言实现了数据结构中常见的八大排序算法,它们分别是 插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序和计数排序 。在排序算法的实现过程中,每种算法都有其独特的特点和适用场景。插入排序通过逐步构建有序序列来排序,希尔

    2024年01月24日
    浏览(38)
  • C++排序算法:归并排序详解

    一、归并排序 二、基本算法         1、分离         2、合并         3、图片讲解 三、代码实现         1、分离函数         2、合并函数          3、完整代码          4、样例 四、总结          归并排序 (Merge Sort)是建立在归并操作上的一种既有效又稳

    2024年02月12日
    浏览(32)
  • 【初阶算法4】——归并排序的详解,及其归并排序的扩展

    目录 前言 学习目标: 学习内容: 一、介绍归并排序 1.1 归并排序的思路 1.2 归并排序的代码 1.2.1 mergesort函数部分  1.2.2 process函数部分  1.2.3 merge函数部分  二、AC两道经典的OJ题目 题目一:逆序对问题 题目二:小和问题  三、练习一道LeetCode的题目 四、总结在什么情况下使

    2024年02月08日
    浏览(29)
  • 算法基础(一)| 快速排序和归并排序详解

    ⭐写在前面的话:本系列文章旨在复习算法刷题中常用的基础算法与数据结构,配以详细的图例解释,总结相应的代码模板,同时结合例题以达到最佳的学习效果。本专栏面向算法零基础但有一定的C++基础的学习者。若C++基础不牢固,可参考:10min快速回顾C++语法,进行语法

    2024年02月21日
    浏览(35)
  • 【算法】归并排序 详解

    排序: 排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来的操作。 稳定性: 假定在待排序的记录序列中,存在多个具有相同的的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中, r[i] = r[j], 且 r[i] 在 r[j] 之前,而

    2024年02月09日
    浏览(25)
  • 【排序算法】 计数排序(非比较排序)详解!了解哈希思想!

    🎥 屿小夏 : 个人主页 🔥个人专栏 : 算法—排序篇 🌄 莫道桑榆晚,为霞尚满天! 什么是计数排序?计数排序的思想是什么?它是如何实现的? 本文会对计数排序进行由浅入深的探究,让你彻底掌握计数排序! ​ 计数排序又称为鸽巢原理,是对哈希直接定址法的变形应

    2024年02月06日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包