归并排序--原理解释和代码优化

本文详细介绍了归并排序的原理,强调了“分治”思想。通过分析原版和优化版的归并排序代码,阐述了如何减少递归调用以提高效率。优化主要体现在归并函数的调整,减少了不必要的函数调用,降低了代码执行时间。同时,文章还探讨了归并排序执行过程与原理图之间的顺序差异,并通过图解展示了优化版的递归执行过程。
摘要由CSDN通过智能技术生成

归并排序原理介绍

归并排序利用“分治”的思想,将一个长度为n的待排数组不断的二分为原来的一半;经过logn次之后,每段就将只剩下1个元素,这样的元素段一共有n段,至此,“归“的部分已经完成。(请结合下图理解)这部分的时间复杂度为logn。
剩下的就是”并“的部分,每次”并“操作都对相邻两段内的元素进行排序,完成排序之后合并为一段,总段数变为一半,经过logn次合并排序之后,整个数组变为有序的一整段,排序完毕。这部分的时间复杂度为n*logn。由于合并过程中的排序需要先把原数组中的元素复制到临时数组,待排好序之后再返回至原数组,所以需要开辟跟原数组大小一样的空间,因此空间复杂度为O(n)。
具体的原理图如下:
在这里插入图片描述

归并排序代码

递归完成”归“部分函数:

//原版
void merge_sort(int p[], int l, int r)
{
	int temp;
	int mid = (l + r) / 2;
	if (r<=l)         
		return;
	merge_sort(p, l, mid);
	merge_sort(p, mid + 1, r);
	merge(p, l, r);
}

//优化版
void merge_sort(int p[], int l, int r)
{
	int temp;
	int mid = (l + r) / 2;
	if (r - l <= 1)         
	{
		if (p[r] < p[l])
		{
			temp = p[r];
			p[r] = p[l];
			p[l] = temp;
		}
		return;
	}
	merge_sort(p, l, mid);
	merge_sort(p, mid + 1, r);
	merge(p, l, r);

优化版本的代码主要是针对"归"函数的分隔次数做出了修改:
归并函数原版中merge_sort( )是进行logn次切割,到最后剩下n段,每段含有一个元素;
归并函数优化版中merge_sort( )是进行(logn)-1次切割,到最后剩下n/2段,每段含有两个或者一个元素;
这样做的好处是分别减少n次、n/2次对merge_sort( )、merge( )的递归调用。我们可以很容易看到,当将n/2段分隔为n段的时候,需要调用merge_sort() n次,但其实际上这n次中的每一次调用都只是执行了内部的if(r<=l) return;然而函数调用的入栈和出栈开销十分大;同理,调用n/2次merge( )函数完成n个无序段到n/2个无序段的合并也是开销巨大的。所以将上述两个操作纳入merge_sort( )中,避免低效的函数调用,可以大大减少代码执行时间。

原版递归调用merge_sort( )函数完成的工作:
在这里插入图片描述
优化版递归调用merge_sort( )函数完成的工作:
在这里插入图片描述
”并“部分函数:

void merge(int p[], int l, int r)
{
	int* tmp=new int[r-l+1];
	int mid = (r-l) / 2;
	int i = 0;
	int j = (r - l) / 2+1;
	for (int k = 0; k < r - l + 1; k++)
		tmp[k] = p[l + k];
	int k = 0;
	while(i<=mid||j<=r-l)
	{
		if (i > mid)
			p[k + l] = tmp[j++];
		else if (j > r-l)
			p[k + l] = tmp[i++];
		else if (tmp[i] < tmp[j])
			p[k + l] = tmp[i++];
		else
			p[k + l] = tmp[j++];
		k++;
	}
	delete[] tmp;
}

因此,优化版的归并排序原理图为:
在这里插入图片描述
介绍到这里,归并排序是不是说完了呢?其实,还有一个有趣的事情是,虽然我们看到原理图里面的归并过程十分清晰,但如果要根据原理图来构思递归代码还是很吃力的。这是为什么?答案就在于,归并排序执行过程与原理图所展现的过程在顺序上有差别。下面,我将通过图解的方式展现merge_sort( )函数的实际执行过程,也方便大家了解整个递归过程(优化版):

蓝色的序号0-9分别表示这九个函数的执行顺序,圆圈序号1-7则表示数组A的排序过程
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值