欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

归并排序

程序员文章站 2022-05-23 11:20:17
...

归并排序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();
}