583-归并排序算法的思想和性能分析

归并排序算法的思想在这里插入图片描述

归并排序算法不仅仅可以做内排序(内存上的排序),还可以做外排序(磁盘上文件的数据的排序)

归并排序算法归就是递归的归,递的过程是缩减数据规模到头,规模小到结果是已知的,然后归的过程是在计算各个规模的结果,累计出原始数据规模的结果。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我们看下面这一行待排序的序列
在这里插入图片描述
要归并,首先要先递,递的过程是在缩小数据规模,对于数组来说,缩小数据规模就是缩小起始和末尾下标的数据的长度,递到序列里只剩下1个元素为头。
序列中起始下标是0,末尾下标是9
在这里插入图片描述
首先,进行递
把原始序列进行分段
我们采用的是二路归并!都是在原数组上操作的,没有开辟额外的空间。

在这里插入图片描述

继续划分
在这里插入图片描述
继续划分
序列中只有1个元素,就认为是已经有序的,
在这里插入图片描述
继续划分
在这里插入图片描述
以上这就是归并排序的递的过程,已经递到头了,元素的左右下标已经是相等了,1个序列只有1个元素,所以每个序列已经是有序了,这就是递归结束的条件

现在要进行归并排序的归并了
相当于是在二叉树中从叶子节点往根节点回退的过程
我们需要申请额外的空间了
因为对于底层的62序列和99序列,我们认为是已经有序的了,它们两个在归的过程中要往父节点归,归的过程中就要把这2个分别有序的序列合并成1个全局有序的序列。
我们定义i,j分别指向这2个序列的起始
在这里插入图片描述
比谁小,先放谁到这个开辟的空间上
62小于99,然后把62放入空间中,然后i++,这个序列只有1个元素,所以结束了
现在j这个序列有1个元素99,然后把99放到空间中
在这里插入图片描述
然后把这个空间中合并的全局的有序序列的结果返回父节点,对应的0-1号的数组位置中。
然后继续向上归
在这里插入图片描述
把序列:62 99和序列:38合并成1个全局的有序序列
同样的,给这两个序列分别定义i和j指向起始,然后开辟额外的空间
i和j比较,谁小,谁先放,j指向的元素小,j先放进去空间中,然后j++,
j越界了,然后把i的序列中的值按顺序放进去。
在这里插入图片描述

然后拷贝到0-2号元素的内存空间中
在这里插入图片描述
以此类推下去。

在这里插入图片描述
在这里插入图片描述
然后就是回退到根节点,合并成最终的整个有序结果:
在这里插入图片描述
在这里插入图片描述

归并排序算法的代码实现

#include <iostream>
using namespace std;

//归并过程函数  O(n)
void Merge(int arr[], int l, int m, int r, int* p)
{
	int idx = 0;
	int i = l;
	int j = m + 1;

	while (i <= m && j <= r)//较小的那个值先放进开辟的数组中 
	{
		if (arr[i] <= arr[j])
		{
			p[idx++] = arr[i++];
		}
		else
		{
			p[idx++] = arr[j++];
		}
	}

	while (i <= m)//i这个序列有剩余元素 
	{
		p[idx++] = arr[i++];
	}

	while (j <= r)//j这个序列有剩余元素 
	{
		p[idx++] = arr[j++];
	}

	//再把合并好的大段有序的结果,拷贝到原始arr数组[l,r]区间内
	for (i = l, j = 0; i <= r; i++, j++)
	{
		arr[i] = p[j];
	}
}

//归并排序递归接口
void MergeSort(int arr[], int begin, int end, int* p)
{
	//递归结束的条件
	if (begin >= end)
	{
		return;
	}

	int mid = (begin + end) / 2;
	//先递,分成两段,递下去 
	MergeSort(arr, begin, mid, p);
	MergeSort(arr, mid + 1, end, p);
	//再归并  [begin, mid]  [mid+1, end] 把两个小段有序的序列,合并成大段有序的序列
	Merge(arr, begin, mid, end, p);
}

//归并排序
void MergeSort(int arr[], int size)
{
	int* p = new int[size];
	MergeSort(arr, 0, size - 1, p);
	delete[]p;
}

int main()
{
	int arr[10];
	srand(time(NULL));

	for (int i = 0; i < 10; i++)
	{
		arr[i] = rand() % 100 + 1;
	}

	for (int v : arr)
	{
		cout << v << " ";
	}
	cout << endl;

	MergeSort(arr, 10);

	for (int v : arr)
	{
		cout << v << " ";
	}
	cout << endl;
}

在这里插入图片描述

归并排序算法的性能分析

对于归并排序算法来说,没有最好和最好情况之说,因为不管是乱序还是已经有序的,都是对半分的,合成出来的都是一个非常完美的二叉树

时间复杂度:
树的层高:O(logn),在每一层,都要进行序列数据的合并,每一层要合并的数据可以看作是n个,是O(n)
所以时间复杂度是O(nlogn)
在这里插入图片描述

空间复杂度:
栈上定义的变量是常量个数,和数据量的大小没有关系
有递归,递归的深度是树的层数是logn,递归占用的内存是O(logn)
有开辟额外的堆空间数组。是O(n)
递归的深度和开辟额外的堆内存空间没有直接关系。
所以,它们是相加的关系。
在这里插入图片描述
所以,我们取大的那个值:O(n)

归并排序是稳定的:
在这里插入图片描述

是稳定的,如果两个序列比较的两个元素的值是相等的,是先把前面序列的那个元素放进去。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

林林林ZEYU

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

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

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

打赏作者

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

抵扣说明:

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

余额充值