6、归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

(1)自上而下的递归(所有的递归都可以用迭代重写,故有第二种方法)

(2)自下而上的迭代

归并排序是建立在合并两个有序数列的基础上的,如何合并两个有序的数列?

首先申请两个数列长度和的空间Temp,比较两个数列的第一个数字,取其中较小的一个存入Temp,将对应数列第一个数字删除,继续比较,如果有数列为空,则将另一数列直接依次存入Temp。

归并过程两两比较,不存在跳跃比较,所以归并排序是一个稳定的排序,归并排序是一个占内存,但效率高稳定的排序。


1、算法步骤

(1)将待排序n个数字划分为n等份,每份长度为1个元素,则n份全部有序;

(2)然后两两归并,得到[n/2]个长度为2或者1的有序子序列;

(3)然后再两两归并.......,如此反复,直到得到长度为n的有序序列。

2、动画演示

 3、复杂度分析

(1)向下递归实现

时间复杂度为O(nlogn):一趟归并需要将所有元素扫描一遍,耗费O(n)时间,由完全二叉树的深度可知,总共需[\log _{2}n]次归并。

空间复杂度为O(n+\log n):需要与原始数列同样数量空间存储归并结果,递归时深度为\log _{2}n的栈空间。

(2)向上迭代实现

时间复杂度也为O(nlogn);避免了递归所需的深度为\log _{2}n的栈空间,空间复杂度为O(n)

4、C++代码实现

递归实现

#include<iostream>
using namespace std;

template<typename T>
/*A[]为待归并的两个数列,tmpA[]存放归并结果,L为第一个序列的左端,R、RightEnd为第二个序列的左端和右端*/
void Merge(T A[], T tmpA[], int L, int R, int RightEnd)
{
	int LeftEnd = R-1;
	int tmp = L;
	int NumElements = RightEnd - L + 1;
	while(L <= LeftEnd && R <= RightEnd)
	{
		if(A[L] <= A[R])//取较小值存入
			tmpA[tmp++] = A[L++];
		else
			tmpA[tmp++] = A[R++];
	}
	while(L <= LeftEnd)//第一个有序数列剩余,直接拼接
		tmpA[tmp++] = A[L++];
	while(R <= RightEnd)//第二个有序数列剩余
		tmpA[tmp++] = A[R++];
	for(int i = 0;i < NumElements;i++,RightEnd--)//将归并的结果存入原来的空间
		A[RightEnd] = tmpA[RightEnd];
}

template<typename T>
void MSort(T A[], T tmpA[],int L,int RightEnd)
{
	int center;
	if(L < RightEnd)//递归调用,直到区间长度为1返回。
	{
		center = (L+RightEnd)/2;
		MSort(A,tmpA,L,center);
		MSort(A,tmpA,center+1,RightEnd);
		Merge(A,tmpA,L,center+1,RightEnd);
	}
}

template<typename T>
void Merge_Sort(T A[],int N)
{
	T* TmpA;
	TmpA = (T*)malloc(N*sizeof(T));
	if(TmpA != NULL)
	{
		MSort(A,TmpA,0,N-1);
		free(TmpA);
	}
	else
		cout<<"空间不足";
}
int main()
{
	int A[] = {15,48,1,84,123,44,5,11,89,43};
	int len = sizeof(A)/sizeof(A[0]);

	Merge_Sort(A,len);
	for(int i =0;i<len;i++)
		cout<<A[i]<<" ";
	return 0;
}

迭代实现

#include<iostream>
using namespace std;
template<typename T>
/*A[]为待归并的两个数列,tmpA[]存放归并结果,L为第一个序列的左端,R、RightEnd为第二个序列的左端和右端*/
void Merge(T A[], T tmpA[], int L, int R, int RightEnd)
{
	int LeftEnd = R-1;
	int tmp = L;
	int NumElements = RightEnd - L + 1;
	while(L <= LeftEnd && R <= RightEnd)
	{
		if(A[L] <= A[R])//取较小值存入
			tmpA[tmp++] = A[L++];
		else
			tmpA[tmp++] = A[R++];
	}
	while(L <= LeftEnd)//第一个有序数列剩余,直接拼接
		tmpA[tmp++] = A[L++];
	while(R <= RightEnd)//第二个有序数列剩余
		tmpA[tmp++] = A[R++];
}

template<typename T>
void Merge_pass(T A[], T TmpA[], int N, int length)
{
	int i;
	for(i = 0; i <= N-2*length; i += 2*length)
		Merge(A, TmpA, i, i+length, i+2*length-1);
	if(i+length < N)/*归并最后两个子列*/
		Merge(A, TmpA, i, i+length, N-1);
	else/*最后只剩下一个子序列*/
	{
		for(int j = i; j < N; j++)
			TmpA[j] = A[j];
	}
}

template<typename T>
void MergeSort(T A[], int N)
{
	int length = 1;//初始化有序子数列长度
	T* TmpA;
	TmpA = (T*)malloc(N*sizeof(T));
	if(TmpA != NULL)
	{
		while(length < N)
		{
			Merge_pass(A, TmpA, N, length);
			length *= 2;
			Merge_pass(TmpA, A, N, length);//可以保证最终结果保存在A中
			length *= 2;
		}
		free(TmpA);
	}
	else
		cout<<"空间不足";
}
int main()
{
	int A[] = {15,48,1,84,123,44,5,11,89,43};
	int len = sizeof(A)/sizeof(A[0]);

	MergeSort(A,len);
	for(int i =0;i<len;i++)
		cout<<A[i]<<" ";
	return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值