二路归并排序及时间复杂度分析

序言

二路归并排序是一种效率极高的递归排序,将数组A化为有序数组时间复杂度为O(nlogn)。

思想

二路归并排序分为拆分数组以及合并两个操作。

切分(自上而下)时间复杂度2*T(n/2)

每次从数组A中间切分,将数组分为[low,mid]以及[mid+1,high]两段,直至不可再分(low不小于high)即最终分成最下层一个一个的数组。当然在代码中不会让他真的变成一个一个数组!用下标圈定范围即可。
自上而下切分

合并(自下而上)时间复杂度T(n)

将两段各自有序的数组合并成一个有序数组,并逐步向上合并,最终得到一个有序数组。

下面举例分析如何进行合并操作,需要三个指针,我设为i,j,k

  1. 比较下面两个数组指针(i,j)所指位置的数值
  2. 将较小的放入上面的有序数组里,例如第一次比较17<28,故将17放入上面有序数组中的第一个位置。此时i++,k++即i,k向后移动一位
  3. 直至下面两个数组其中之一遍历完成,该例子为【17,24】遍历完成,而【28,40】并未遍历完成
  4. 最终将未遍历完的数组剩下部分复制到上面的那个有序数组里
    自下而上合并
辅助数组B的作用

在合并操作中,先将此次需要合并的A数组全部放入B中,即i,j所指向的数组B,没错,他俩实际上在代码中就是一个数组只不过人为的在中间分开了,分为[low,mid],[mid+1,high]两段而已。
再经历上述合并步骤,将这两段数组合并到A数组的原位置中[low,high]中。
即i,j指向的是B数组的元素,而k指向的是A数组的元素

代码

#include<iostream>
using namespace std;


#define n 16

//辅助数组--->空间复杂度O(n)
int* B = (int*)malloc((n + 1) * sizeof(int));

//合并
void merge(int A[], int low, int mid, int high) {
	//将A复制到B
	for (int k = low; k <= high; k++) {
		B[k] = A[k];
	}
	int i, j, k;
	//循环结束条件需要满足左右数组其中之一遍历结束
	for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++) {
		if (B[i] <= B[j])
			A[k] = B[i++];
		else
			A[k] = B[j++];
	}
	//若左数组未遍历结束
	while (i <= mid)A[k++] = B[i++];
	//若右半数组未遍历结束
	while (j <= high)A[k++] = B[j++];
}

//二路归并排序
void mergeSort(int A[], int low, int high) {
	if (low < high) {
		int mid = (low + high) / 2;
		//左半数组--->T(n/2)
		mergeSort(A, low, mid);
		//右半数组--->T(n/2)
		mergeSort(A, mid + 1, high);
		//合并--->T(n)
		merge(A, low,mid, high);
	}
}
int main() {
	int A[16] = {24,17,40,28,13,14,22,32,40,21,48,4,47,8,37,18};
	mergeSort(A, 0, 15);
	for(int i  =0;i<n;i++)
		cout << A[i]<<" ";
	return 0;
}

时间复杂度分析

  1. 首先,每次将数组分为左半数组和右半数组mergeSort时间复杂度均为T(n/2)
  2. 合并操作merge空间复杂度为T(n)
  3. 故实际时间复杂度公式为时间复杂度

一、递归树法

递归树法
每一层都是上一层的一半,共有logn层,而每一层都有一次时间复杂度为O(n)的合并操作,故时间复杂度为O(nlogn)

二、主定理法(推荐)

主定理法
该式中a = 2 , b =2 , k = 1 满足第二个式子 即时间复杂度为o(nlogn)

------------思想以及图片摘取自北航童咏昕教授算法公开课,代码摘取自王道考研数据结构

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bia!

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

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

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

打赏作者

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

抵扣说明:

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

余额充值