归并排序

归并排序Merging Sort

1. 稳定
2. 需要开辟辅助空间, 因而基本不会用在内部排序中, 反而常用于外排序

将两个或两个以上的有序表组合成一个新的有序表。
二路归并过程描述:
初始:            49 38 65 97 76 13 27
一趟归并之后:    (38 49) (65 97) (13 76) (27)
两趟归并之后:    (38 49 65 97) (13 27 76)
三趟归并之后:    (13 27 38 49 65 76 97)
核心操作是将一维数组中前后相邻的两个有序序列归并为一个有序序列。

算法1 二路归并核心

/*
A[] 原始待排序的元素序列
TmpA[] 临时存放的空间
假设A里面有两个子序列
L 是左边子序列的起始位置
R 是右边子序列的起始位置
RightEnd 是右边子序列终点位置
*/
void Merge( ElementType A[], ElementType TmpA[], int L, int R, int RightEnd )
{
	LetfEnd = R - 1; /*左边子序列终点位置, 假设左右子序列挨着*/
	Tmp = L; /*存放结果的数组的初始报位置*/
	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( L <= LeftEnd ) /*直接复制右边剩下的*/
	/*把结果导回到A*/
	for( i=0; i<NumElements; i++, RightEnd--)
		A[RightEnd] = TmpA[RightEnd];
}
时间复杂度: O(N logN)
空间复杂度: O(N)

算法2 递归实现归并

/*
A[] 带排序的原始序列
TmpA[] 存放结果的临时空间
L 左序列的起始位置
RightEnd 右子序列的终点位置
-------------------------------------
|LS| | | | | | | | | |RE|
_____________________________________
假设两个子序列是挨着的(连续的)
*/
void MSort(ElementType A[], ElementType TmpA[], int L, int RightEnd)
{
	int Center;
	if ( L < RightEnd )
	{
		Center = (L + RightEnd) / 2;
		MSort(A, TmpA, L, Center); /*递归处理左边*/
		MSort(A, TmpA, Center+1, RightEnd); /*递归处理右边*/
		Merge(A, TmpA, L, Center+1, RightEnd);
	}
}

T = O(N logN)

算法3

void Merge_Sort( ElementType A[], int N )
{
	ElementType *TmpA;
	TmpA = malloc(N * sizeof(ElementType));
	if (TmpA != NULL)
	{
		MSort(A, TmpA, 0, N-1);
		free( TmpA );
	}
	else
		Error();
}

对于临时辅助空间TmpA, 一开始申请, 而不在Merge函数内部申请,
原因是Merge被多次调用, 如果在Merge内部申请空间,将会导致频繁
调用malloc和free。

算法4 非递归实现归并

/*
一趟归并的描述实现
length 当前有序子列的长度
*/
void Merge_pass( ElementType A[], ElementType TmpA[], int N, int length )
{
	for( i=0; i<N-2*length; i += 2*length )
	{
		/*Merge1与Merge实现相同, 但是不做最后的那步骤(把数据从TmpA复制到A)*/
		Merge1( A, TmpA, i, i+length, i+2*length-1 );
	} 
	if ( i+length < N ) /*归并最后两个子序列*/
		Merge1(A, TmpA, i, i+length, N-1);
	else /*最后只剩1个序列*/
	{
		for( j=i; j<N; j++)
			TmpA[j] = A[j];
	}
}

void Merge_Sort( ElementType A[], int N )
{
	int length = 1; /*初始化子序列长度*/
	ElementType *TmpA = malloc(N * sizeof(ElementType));
	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
		Error();
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值