排序算法——“史莱姆式”的归并算法

本文介绍了归并排序算法,将其形象地比喻为“史莱姆式”算法,详细阐述了算法的基本思想、实现过程、时间复杂度和空间复杂度。归并排序采用分治策略,通过递归分解序列再合并,保证了排序的稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

鸽了一天没更新了,今天简单地来给大家介绍一下归并算法。
在这里插入图片描述
相信大家刚开始学归并算法时,书上都会有这样一张图,这张图我们从上往下看,首先是分解的过程,将原本无序的序列分解成若干个包含单个元素的序列,然后把这些序列看作起点,对它们执行归并操作,其中归并操作的步骤如下:
(1)申请空间,使其大小为两个已经排序的序列之和,该空间用来存放合并后的序列。
(2)设定两个指针,最初位置分别为两个已经排序序列的起始位置。
(3)比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并将指向较小元素的指针移动到下一个位置。
(4)重复步骤三直到某一指针超出序列尾。
(5)将另一序列剩下的所有元素直接复制到合并序列尾。

基本思想

归并排序采用经典的分治策略(将问题成一些小的问题然后递归求解,的阶段将前一阶段得到的所有答案“修补”在一块儿,即分而治之),是建立在归并操作上的一种有效的排序算法。而分治策略往往就涉及到递归的思想,所以我们的算法实现也涉及递归的思想。

为什么说它是“史莱姆式”算法

这个是博主自己命名的(骄傲),因为史莱姆最传统的技能就是“分裂”再“聚合”,合成更强的史莱姆(大雾)。日漫里经常出现的词“翻修”也类似于此,将组织分解再重整,就可以达到强化肉体、治疗疾病的功能。

算法实现

递归版本:

void merge(vector<int>& v, vector<int>::iterator left, vector<int>::iterator mid, vector<int>::iterator right)
{
	vector<int> help;
	auto iter_1 = left, iter_2 = mid + 1;
	while (iter_1 <= mid && iter_2 <= right)
		help.push_back(*iter_1 > *iter_2 ? *iter_2++ : *iter_1++);
	while (iter_1 <= mid)
		help.push_back(*iter_1++);
	while (iter_2 <= right)
		help.push_back(*iter_2++);

	for (size_t i = 0; i < help.size(); ++i)
		*(left + i) = help[i];
}

void sort_process(vector<int>& v, vector<int>::iterator left, vector<int>::iterator right)
{
	if (left < right)
	{
		auto mid = left + (right - left) / 2;
		sort_process(v, left, mid);
		sort_process(v, mid + 1, right);
		merge(v, left, mid, right);
	}
}

void merge_sort(vector<int>& v)
{
	if (v.size() < 2)
		return;
	sort_process(v, v.begin(), v.end() - 1);
}

算法复杂度

时间复杂度:O(nlog2n),而且要注意归并排序是相对稳定的算法(不是指稳定性,而是指算法对不同序列的时间复杂度相对稳定),也就是说归并算法的时间复杂度与序列的有序程度没太大关系,最好最坏的情况下也是 O(nlog2n) ,其中 O(log2n) 是因为分解和归并的过程中每次都对序列进行折半操作,O(n) 是单次归并操作的时间复杂度。
空间复杂度:O(n+log2n),亦可写成O(n),是因为对比起 n ,log2n是相较可以忽略的小值。其中 n 是 merge 内使用到的辅助数组 vector help所占用的内存空间;而 log2n是递归所占用的栈空间。

算法稳定性

我们看下面这句代码:

help.push_back(*iter_1 > *iter_2 ? *iter_2++ : *iter_1++);

这里就可以看出merge_sort属于稳定的,因为iter_1永远指向范围内前半部分的元素,而iter_2指向后半部分的元素,而当iter_1 <= iter_2时,我们将iter_1所指向的元素放入help序列,说明在两者相同时我们选择先放入位置靠前的元素,就保持了稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值