分治---归并排序

数组排序任务可以如下完成:

  • 把前一半排序
  • 把后一半排序
  • 把两半归并到一个新的有序数组,然后再拷贝回原数组,排序完成

将两个排序好的数组归并过程如下:
在这里插入图片描述
红色的 1 是左边起始位置;
绿色的 2 是右边起始位置;
灰色的 最右边 是右边终点位置;

代码:

#include<iostream>
using namespace std;
typedef int ElementType;
//L = 左边起始位置, R = 右边起始位置, RightEnd = 右边终点位置
void Merge(ElementType A[], ElementType TmpA[],int L, int R, int RightEnd)
{
	int LeftEnd = R - 1;
	int len = RightEnd - L;
	int i = L;
	while (L<=LeftEnd && R<=RightEnd)   //当其中一个数组排完后立即停止
	{
		if (A[L]>A[R])
			TmpA[i++] = A[R++];
		else
			TmpA[i++] = A[L++];
	}
	while (L <= LeftEnd)     //剩下的数组全加上去
		TmpA[i++] = A[L++];
	while (R <= RightEnd)    //剩下的数组全加上去
		TmpA[i++] = A[R++];
	for (int i = 0; i <= len; i++,RightEnd--)
		A[RightEnd] = TmpA[RightEnd];
}

void MSort(ElementType A[], ElementType TmpA[], int L, int RightEnd)  //要排序的部分为 L 到 RightEnd
{
	if(L<RightEnd)
	{
		int center = (L + RightEnd) / 2;
		MSort(A,TmpA,L,center);             // 左半部分继续递归
		MSort(A,TmpA,center+1,RightEnd);    // 右半部分继续递归
		Merge(A,TmpA,L,center+1,RightEnd);  // 将上面部分归并
	}
}

void Merge_Sort(ElementType A[], int N) //用堆申请内存排序完再 free 就不会浪费栈内存了
{
	ElementType *TmpA = (int *)malloc(N*sizeof(ElementType));
	if (TmpA != NULL)
	{
		MSort(A, TmpA, 0, N - 1);
		free(TmpA);
	}
	else
		cout << "空间不足";
}

int main()
{
	int a[] = { 4, 6, 1, 8, 9, 3, 7, 0 };
	int len = sizeof(a) / sizeof(a[0]);
	Merge_Sort(a, len);
	for (int i = 0; i < len; i++)
		cout << a[i] << " ";
	return 0;
}

我学到的:

通过使用分治算法的思想来对数组进行排序(这里叫做归并排序),分治算法的核心思想就是把一个问题分解n个小问题,然后把这n个小问题分别解决,最后再把这n个小问题的结果合并便可以得到结果了。(分解–解决–合并)

此题思路是:
先将一个未排列的数组二分、二分、再二分,当分到只有一个元素时再归并,归并就是将原来二分的两个数组合并成一个,归并的时候顺便排序(历遍两个数组排到一个数组上),重复此操作,二分多少次就归并多少次,最后得到的就是一个排好序数组

对n个元素进行排序的时间复杂度:

T(n) = 2 * T(n/2) + a * n (a是常数,具体多少不重要)

= 2 * (2 * T(n/4) + a * n/2)+a * n

= 4 * T(n/4) + 2a * n

= 4 * (2 * T(n/8) + a * n/4)+2 * a * n

= 8 * T(n/8) + 3 * a * n

……

= 2k  * T(n/2k) + k * a * n


一直到n/2k = 1 (此时k = log2n)

T(n)= 2k * T(1) + k * a * n

= 2k + k * a * n

= n + a * (log2n) * n


故复杂度为 O(n * logn)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值