算法回顾之归并排序c++实现


前言

本文继续排序算法的回顾。本文主要是针对归并排序进行分析,分别从递归的角度和分治的角度对归并进行认识,并附上c++的实现


一、归并排序介绍(代码在大标题二)

同样,这里我们以一个乱序数组为例。有数组 a[5]

a[0]a[1]a[2]a[3]a[4]
32710

len = 5
startIndex = 0
endIndex = n - 1 = 5 - 1 = 4

1.1 思路

归并排序的中心思路可以概括为从局部有序到整体有序。具体来说,就是可以将原数组进行分割(分治),分别进行运算(递归),实现局部有序,然后通过一个外排进而实现整体有序

1.2 基本流程

结合a[5],就是先将数组切成两半
在这里插入图片描述
然后进行局部的排序,并借助两个指针实现外排(借助辅助数组,a和b中的较小值填入辅助数组,并且右移,直到其中一个指针遍历了其所在的子数组的全部元素,结束并将另外的数组的剩余元素全部拷贝到辅助数组),进而实现整体有序。(图片这里仅展示了第一次分治的过程,实际上伴随着递归,子数组也会被再一次分治,外排,直到无法进行分割,直观来说,就是辅助数组被构建了logN次)
在这里插入图片描述
最后将辅助数组数据拷贝到原数组即可。

时间复杂度分析:

  • 子数组元素的数量是原数组元素的数量的一半
    T(N) = 2T(N/2)
  • 此外,外派的复杂度为O(N),故有
    T(N) = 2T(N/2) + O(N)
  • 根据Master公式有
    log(b, a) > d 复杂度为O(N^log(b, a) )
    log(b, a) = d 复杂度为O((N^d) * logN)
    log(b, a) < d 复杂度为O(N^d )
    所以有归并的时间复杂度为:O(N*logN)

二、代码

#include <iostream>
#include <vector>
using namespace std;

void Merge(vector<int> &v, int start, int mid, int end)
{
	vector<int> temp(end - start + 1, 0);
	int i = 0;
	int p1 = start;	//左侧指针
	int p2 = mid + 1;	//右侧指针
	//越界时跳出
	while (p1 <= mid && p2 <= end)
	{
		temp[i++] = v[p1] < v[p2] ? v[p1++] : v[p2++];
	}
	//拷贝剩余的数据到辅助数组
	while (p1 <= mid)
	{
		temp[i++] = v[p1++];
	}
	while (p2 <= end)
	{
		temp[i++] = v[p2++];
	}
	//数据拷贝
	for (i = 0; i < temp.size(); i++)
	{
		v[start + i] = temp[i];
	}
}

void SortProcess(vector<int> &v, int start, int end)
{
	if (start == end)
	{
		return;
	}
	int mid = start + ((end - start) >> 1);
	SortProcess(v, start, mid);
	SortProcess(v, mid + 1, end);
	//合并
	Merge(v, start, mid, end);
}

void MergeSort(vector<int> &v)
{
	if (v.size() < 2)
	{
		return;
	}
	//分插
	SortProcess(v, 0, v.size()-1);
}


int main()
{
	//测试
	vector<int> v = { 3,2,7,1,0 };

	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << "\t";
	}
	cout << endl;

	MergeSort(v);

	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << "\t";
	}
	cout << endl;

	system("pause");
	return 0;
}

总结

笔者在回顾的时候,这段编码还是错误挺多次的,主要问题出现在Merge函数部分,即辅助数组构建时候出了问题,究其原因,主要是对递归的理解不到位。总结来讲,归并排序的各个阶段不难理解,但是当这些内容串联起来是容易犯一些错误。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Claude的羽毛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值