C++数据结构X篇_24_归并排序(稳定的排序)

本篇参考十大经典排序算法-归并排序算法详解进行整理和补充。

1. 什么是归并排序

1.1 概念

归并排序(Merge sort) 是建立在归并操作上的一种有效的排序算法,归并排序对序列的元素进行逐层(递归)折半分组,然后从最小分组开始比较排序,合并成一个大的分组,逐层进行,最终所有的元素都是有序的。
归并排序基本思想:将两个有序序列合并成一个有序序列。

1.2 算法原理

这是一个无序数列:4、5、8、1、7、2、6、3,我们要将它按从小到大排序。按照归并排序的思想,我们要把序列逐层进行拆分
在这里插入图片描述
序列逐层拆分如下
在这里插入图片描述
然后从下往上逐层合并,首先对第一层序列1(只包含元素4)和序列2(只包含元素5)进行合并

创建一个大序列,序列长度为两个小序列长度之和,p1、p2指针分别指向两个小序列的第一个元素,p指向大序列的第一个元素
在这里插入图片描述
比较p1、p2指向的元素,4小于5,将4填入p指向的元素,p、p1往右移一位
在这里插入图片描述
此时,序列1已经没有元素,将序列2的元素依次填入大序列中
在这里插入图片描述
序列8和1,序列7和2,序列6和3,用同样的方式填入新的序列
在这里插入图片描述
接着,以4、5为序列1,1、8为序列2,继续进行合并

创建一个序列长度为4的大序列,p1指向序列1的第一个元素4,p2指向序列2的第一个元素1,p指向大序列的第一个元素
在这里插入图片描述
4和1比较,4大于1,1填入p指向的元素,p、p2往右移一位

在这里插入图片描述
4和8比较,4小于8,4填入p指向的元素,p、p1往右移一位
在这里插入图片描述
5和8比较,5小于8,5填入p指向的元素,p、p1往右移一位
在这里插入图片描述
自此,序列1已经没有元素,将序列2的元素依次填入大序列中
在这里插入图片描述
序列2、7和序列3、6以同样的方式合并成新的序列
在这里插入图片描述
最后,将序列1、4、5、8和序列2、3、6、7以同样的方式继续合并成新的序列
在这里插入图片描述
至此所有的元素都是有序的

1.3 算法实现

#include <iostream>
#include <time.h>
#include <sys/timeb.h>

using namespace std;

#define MAX 10

//获取系统当前时间,ms为单位
long getSystemTime()
{
	struct timeb tb;
	ftime(&tb);
	return tb.time * 1000 + tb.millitm;
}


//打印数组
void printArr(int arr[])
{
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

//初始化数组
int* CreateArray()
{
	//数据放到堆区
	int* arr = (int*)malloc(sizeof(int)*MAX);
	//生成随机数
	srand((unsigned int)time(NULL));
	for (int i = 0; i < MAX; i++)
	{
		arr[i] = rand() % MAX;
	}

	return arr;
}

//合并算法,从小到大
void Merge(int arr[], int start, int end, int mid, int* tmp)
{
	int i_start = start;
	int i_end = mid;

	int j_start = mid + 1;
	int j_end = end;

	//表示辅助空间有多少元素
	int length = 0;

	//合并两个有序序列
	while (i_start <= i_end && j_start <= j_end)
	{
		if (arr[i_start] < arr[j_start])
		{
			tmp[length] = arr[i_start];
			length++;
			i_start++;
		}
		else
		{
			tmp[length] = arr[j_start];
			length++;
			j_start++;
		}
	}

	//有一个序列会有剩下的元素,无法知道是哪个,进行遍历将剩余元素拷贝到辅助空间
	//i这个序列
	while (i_start <= i_end)
	{
		tmp[length] = arr[i_start];
		i_start++;
		length++;
	}

	//j这个序列
	while (j_start <= j_end)
	{
		tmp[length] = arr[j_start];
		j_start++;
		length++;
	}

	//辅助空间数据覆盖原空间
	for (int i = 0; i < length; i++)
	{
		arr[start + i] = tmp[i];
	}
}

//归并排序,tmp是辅助空间,排序完的结果放到其中
void MergeSort(int arr[], int start, int end, int* tmp)
{
	//递归结束条件
	if (start >= end)
	{
		return;
	}

	int mid = (start + end) / 2;
	//递归 分组
	//左半边
	MergeSort(arr, start, mid, tmp);
	//右半边
	MergeSort(arr, mid + 1, end, tmp);

	//合并
	Merge(arr, start, end, mid, tmp);
}



int main()
{
	int* myArr = CreateArray();

	//辅助空间
	int* tmp = (int*)malloc(sizeof(int)*MAX);

	printArr(myArr);
	MergeSort(myArr, 0, MAX - 1, tmp);
	printArr(myArr);

	//释放空间
	free(tmp);
	free(myArr);

	return 0;
}

2. 归并排序算法特点

2.1 时间复杂度

归并排序算法每次将序列折半分组,共需要logn轮,因此归并排序算法的时间复杂度是O(nlogn)

2.2 空间复杂度

归并排序算法排序过程中需要额外的一个序列去存储排序后的结果,所占空间是n,因此空间复杂度为O(n)

2.3 稳定性

归并排序算法在排序过程中,相同元素的前后顺序并没有改变,所以归并排序是一种稳定排序算法

  1. 视频:归并排序1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

十月旧城

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

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

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

打赏作者

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

抵扣说明:

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

余额充值