排序算法进阶——归并排序【详细图解,递归和非递归】

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

归并算法

在了解归并排序之前让我们先了解一下归并这一算法吧!

归并算法一般应用于合并两个已经有序的序列,使合并后的序列也有序,是一个时间复杂度为O(N)的算法,不过一般要借助两个要排序的序列的元素个数个额外的空间。

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

基本思想:

既然要排序的两个序列已经有序,那么就可以先申请两个序列元素之和大小的空间,再比较两个序列的第一个元素的大小,将小的那一个元素放在申请的空间的第一个【假设排升序】,再让放入的那个元素之后的一个元素与那个第一次比较时没放入的元素比较,再把小的那一个放入申请空间的第二个位置上…

直到有有一个序列已经全部放入了申请的空间,此时另一序列的剩下的元素都大于放完序列的最大值,所以可以直接将它剩下的元素全部放入申请空间。

如下图
排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

具体代码实现:

定义两个指针指向两个序列的第一个元素,如果左侧序列的指针指向的元素更小就把它放入申请的空间,否则将右侧序列的元素放入申请空间
借此构成一个循环,循环结束条件是两个指针中有一个指向序列的最后一个元素之后就结束

排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

归并排序

基本思想

有了归并算法后,我们知道只要要排序的两个序列是有序的我们就可以轻松地排出一个有序序列

同理如果将一个序列分成两半,如果它坐边有序右边也有序,就可以直接用归并算法整个序列有序。
那么怎么让左右两边的序列有序呢?
我们知道如果序列中只有一个序列时那它肯定是有许的,既然如此,
我们让要排序列的左侧序列和右侧的元素个数为1
此时,不就左右有序可以归并了吗。

如何完成这个操作呢?

有两个方法

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

方法一:递归

将序列分成两半在,分成的两半再分别分成两半…。直到左序列和右序列的元素个数都为1时再从小区间归并到大区间
如下图

排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
该过程可用递归实现。

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

实现方法:

先申请于序列等大的空间,再创建用于递归的函数
排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
再实现递归函数

先将左右区间递归到都只有一个元素
排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法

浅浅画了一下递归展开图
排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法

排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
left=2,right=3时也类似

做完以上的递归之后,左右区间的元素个数就都只有1了(如上图的左区间【0-0】,右区间【1~1】),此时从大区间向小区间的递归就结束了
然后开始向下执行代码,进行归并,
小区间时的代码执行完后,会自动返回到调用这一小区间的位置,即更大的区间的函数中,继续向下执行代码

排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
具体过程可参考下图【注意:left和right是下标
排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

完整代码:

void D_MereSort(int a[], int left, int right, int* tmp)
{
	//left和right分别为递归区间的左右端点的下标
	//把要归并的两边的区间递归到各只有1个元素就停
	if (left >= right)
		return;
	//mid为递归区间中间下标
	int mid = (left + right) / 2;

	//递归
	D_MereSort(a, left, mid, tmp);
	D_MereSort(a, mid+1, right, tmp);

	//定义begin和end接受left和right
	//防止left和right改变,导致出错
	int begin1 = left, end1 = mid;
	int begin2 = mid+1, end2 = right;
	//i必须有且值只能是  左侧区间的左端点  即left
	int i = left;

	//归并算法
	while (begin1 <= end1 && begin2 <=end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	int j = left;
	//将归并好的放回要排序的数组
	for (; j<=right; j++)
		a[j] = tmp[j];
}

//归并排序(递归)
void MergeSort1(int a[], int n)
{
	//创建临时空间,方便归并
	int* tmp = (int*)malloc(sizeof(int) * n);
	//用于递归的函数
	D_MereSort(a, 0, n - 1, tmp);
	//释放申请空间
	free(tmp);
}

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

方法二:利用下标变化直接在数组中归并【非递归】

如下图
排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法

实现方法:

设gap为左右区间的元素个数
j为循环变化的下标,这样可以将
归并的区间划分为
【i,i+gap-1】【i+gap,i+2*gap-1】
排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
将区间划分为【i,i+gap-1】【i+gap,i+2*gap-1】
可能会出现越界的情况

  • 其中i+gap-1越界和i+gap越界的处理方法相同
  • i+2*gap-1
    如下图
    排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法

排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法

排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

完整代码:

void MergeSort2(int a[], int n)
{
	//申请空间
	int* tmp = (int*)malloc(sizeof(int) * n);
	//gap表示归并的左右区间的元素个数
	int gap = 1;
	int j = 0;
	while (gap < n)//gap不能等于数组的总元素个数
	{
		for (j = 0; j < n; j += 2 * gap)
		{	
			int i = j; //防止循环变量改变,影响循环

			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;

			if (begin2 >= n)//右区间  左端点越界,就直接可以结束
				break;
			if (end2 >= n)//右区间  右端点越界,就将它改为n-1
				end2 = n - 1;
			//归并
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[i++] = a[begin1++];
				}
				else
				{
					tmp[i++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[i++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[i++] = a[begin2++];
			}
		}
		int z = 0;
		//归并结束后,将归并完成的拷贝回去
        //为下次循环的归并做准备
		for (z = 0; z < n; z++)
			a[z] = tmp[z];
		
		gap *= 2;
	}
}

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

归并排序的时间复杂度

归并排序的递归版本是将区间从大向小分,一次一半
我们可以将该过程类似二叉树
排序算法进阶——归并排序【详细图解,递归和非递归】,c语言,算法,排序算法
我们把每一层归并操作消耗的时间记作n。
现在,我们只需要知道这棵树的高度h,用高度h乘以每一层的时间消耗n,就可以得到总的时间复杂度O(n∗h)。从归并排序的原理和递归树,可以看出来,归并排序递归树是一棵满二叉树。
而满二叉树的高度大约是log2n
所以,归并排序递归实现的时间复杂度就是O(nlogn)。

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

归并排序的空间复杂度

归并排序需要借助与数组等大的区间
所以
归并排序的空间复杂度为O(N)

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一

归并排序的稳定性

归并排序采用分治策略,将序列递归地分成短序列,然后将各个有序的短序列合并成一个有序的长序列,不断合并直到原序列全部排好序。
在合并过程中,如果两个当前元素相等时,归并排序会把处在前面的序列的元素保存在结果序列的前面,从而保证了稳定性。

所以归并排序是稳定的

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一
以上就是全部内容了,如果对你有帮助的话,可以点赞支持一下!!!文章来源地址https://www.toymoban.com/news/detail-820017.html

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

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

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

相关文章

  • 排序算法大全:冒泡排序【含优化】,选择排序【含优化】,直接插入排序,希尔排序,堆排序,快速排序【含3种实现版本及非递归实现】,归并排序【含非递归实现】。详细图解,文字解释,代码实现,性能分析。

    目录  一、冒泡排序 1、冒泡排序思想 2、冒泡排序算法的性能分析 二、选择排序 1、选择排序思想 2、选择排序算法的性能分析   三、直接插入排序 1、直接插入排序思想 2、直接插入排序算法的性能分析 四、希尔排序 1、希尔排序思想 2、希尔排序算法的性能分析 五、堆排

    2024年02月20日
    浏览(58)
  • 七大排序(含快排+归并的递归版和非递归版)

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

    2024年01月20日
    浏览(41)
  • 数据结构排序——详细讲解归并排序(c语言实现递归及非递归)

    上次是快排和冒泡:数据结构排序——详解快排及其优化和冒泡排序(c语言实现、附有图片与动图示意) 今天为大家带来归并排序 归并排序是一种分治算法,它将序列分成两个子序列,分别对 子序列进行排序 ,然后将排序好的子序列 合并起来 。这个过程可以 递归 地进行,

    2024年01月22日
    浏览(67)
  • 【算法与数据结构】归并排序的代码实现(详细图解)以及master公式的讲解

    目录 1、归并排序  1.1、算法描述  1.2、图解说明 2、代码实现  3、master公式 3.1、公式以及结论 3.2、适用于某些特殊的递归 3.3、计算归并排序的时间复杂度 归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用 递归 或者说是 分治法 (Divide and Conquer)的一个非

    2024年02月08日
    浏览(62)
  • 插入排序,选择排序,交换排序,归并排序和非比较排序(C语言版)

    前言         所谓排序,就是将一组数据按照递增或者递减的方式进行排列,让这组数据变得有序起来。排序在生活中运用的是十分广泛的,各行各业都用到了排序,比如我们在网购的时候就是按照某种排序的方式来选择东西的。所以去了解排序的实现也就是很重要的了。

    2024年02月09日
    浏览(43)
  • 排序算法:快速排序(三种排序方式、递归和非递归)

    朋友们、伙计们,我们又见面了,本期来给大家解读一下有关排序算法的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏: C语言:从入门到精通 数据结构专栏: 数据结构 个  人  主  页 : stackY、 目录 前言: 1.快速排

    2024年02月09日
    浏览(39)
  • 快速排序算法的递归和非递归

    基本思路 选择一个基准值,将数组划分三个区域,小于基准值的区域位于左侧,等于基准值的区域位于中间,大于基准值的区域位于右侧。将大于和小于区域继续进行分区,周而复始,不断进行分区和交换,直到排序完成 递归 思路: 步骤1: 在当前分区范围[l,r]中随机选中一

    2024年02月09日
    浏览(49)
  • 【数据结构与算法】归并排序详解:归并排序算法,归并排序非递归实现

    归并排序是一种经典的排序算法,它使用了分治法的思想。下面是归并排序的算法思想: 递归地将数组划分成较小的子数组,直到每个子数组的长度为1或者0。 将相邻的子数组合并,形成更大的已排序的数组,直到最终得到一个完全排序的数组。 归并排序的过程可以分为三

    2024年01月22日
    浏览(70)
  • 排序算法:归并排序(非递归)

    先赞后看,养成习惯!!!^ _ ^3 ❤️ ❤️ ❤️ 码字不易,大家的支持就是我坚持下去的动力。点赞后不要忘了 关注 我哦! 所属专栏:排序算法 步骤如下: 1.先两两归并,两个为一组 2.然后根据每组的距离gap,分配组数进行排序 3.gap每次扩大2的倍数 4.注意一些细节:首先注

    2024年03月24日
    浏览(38)
  • 非递归算法——快速排序、归并排序

    哈喽大家好,我是保护小周ღ,本期为大家带来的是常见排序算法中的 快速排序、归并排序,非递归算法, 分享所有源代码,粘贴即可运行,保姆级讲述 , 包您一看就会,快来试试吧~ 目录 一、递归的缺陷 1.1 栈是什么,数据结构“栈”又是什么,他们之间有什么区别?

    2023年04月08日
    浏览(72)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包