第10章 归并排序

【归并】

归并(Merging) :是指将两个或两个以上的有序序列合并成一个有序序列。若采用线性表(无论是那种存储结构)易于实现,其时间复杂度为O(m+n) 。

归并思想实例:两堆扑克牌,都已从小到大排好序,要将两堆合并为一堆且要求从小到大排序。

  1. 将两堆最上面的抽出 (设为 C 1 C_1 C 2 C_2 ) 比较大小,将小者置于一边作为新的一堆 (不妨设 C 1 C_1 < C 2 C_2 );再从第一堆中抽出一张继续与 C 2 C_2 进行比较,将较小的放置在新堆的最下面;
  2. 重复上述过程,直到某一堆已抽完,然后将剩下一堆中的所有牌转移到新堆中。

【排序思想】

① 初始时,将每个记录看成一个单独的有序序列,则 n n 个待排序记录就是 n n 个长度为 1 1 的有序子序列;

② 对所有有序子序列进行两两归并,得到 n 2 \lceil \frac{n}{2} \rceil 个长度为 2 2 1 1 的有序子序列——一趟归并;

③ 重复② ,直到得到长度为 n n 的有序序列为止。

上述排序过程中,子序列总是两两归并,称为2-路归并排序。其核心是如何将相邻的两个子序列归并成一个子序列。设相邻的两个子序列分别为: { R [ k ] , R [ k + 1 ] , , R [ m ] } \left\{ R[k], R[k+1], …, R[m]\right\} { R [ m + 1 ] , R [ m + 2 ] , , R [ h ] } \left\{ R[m+1], R[m+2],…, R[h]\right\} ,将它们归并为一个有序的子序列: { D R [ l ] , D R [ l + 1 ] , , D R [ m ] , D R [ m + 1 ] , , D R [ h ] } \left\{DR[l], DR[l+1], …, DR[m], DR[m+1], …, DR[h] \right\}

完整代码如下:

#include <stdio.h>

#define	TRUE		1			//真 
#define	FALSE		0			//假
#define	OK			1			//通过
#define	ERROR		0			//错误
#define MAXSIZE 20					//用作示例的顺序表的最大长度
#define LT(a,b) ((a)<(b))					
#define LQ(a,b) ((a)<=(b))
typedef int Status;

/* 记录类型 */
typedef int KeyType;				//定义关键字类型为整数类型
typedef struct						//顺序表结构 
{
	KeyType key;					//关键字项 
	//使用结构体便于使用中扩展 
}RcdType;

/* 顺序表类型 */
typedef struct
{
	RcdType r[MAXSIZE+1];			//r[0]闲置或用作哨兵单元
	int length;						//顺序表长度 
}SqList_sort;

//1.创建一个任意顺序的序列。
Status CreateSortList(SqList_sort *L)
{
	printf("请输入元素个数:"); 
	scanf("%d", &((*L).length));
	
	if((*L).length > MAXSIZE)
		return ERROR;
	printf("请依次输入元素的关键字:\n"); 
	for(int i = 1; i <= (*L).length; i++)
		scanf("%d", &((*L).r[i].key));

	return OK;
}

//2.输出序列L。
void Traverse(SqList_sort L)
{
	for(int i = 1; i <= L.length; i++)
		printf("%d ", L.r[i].key);	
	printf("\n");
}


//3.算法10.12:将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]。
void Merge(RcdType SR[], RcdType TR[], int i, int m, int n)
{
	int j, k;
	
	for(j = m+1, k = i; i <= m && j <= n; ++k)			//将SR中记录由小到大地并入TR 
	{
		if(LQ(SR[i].key, SR[j].key))
			TR[k] = SR[i++];
		else
			TR[k] = SR[j++];
	}
		
	while(i<=m)								//将剩余的SR[i..m]复制到TR 
		TR[k++] = SR[i++];
	
	while(j<=n)								//将剩余的SR[j..n]复制到TR 
		TR[k++] = SR[j++];
}

//4.算法10.13:将SR[s..t]归并排序为TR[s..t]。 
void MSort(RcdType SR[], RcdType TR[], int s, int t)
{
	int m;
	RcdType R[MAXSIZE+1];
	
	if(s==t)
		TR[s] = SR[s];
	else
	{
		m = (s+t)/2;						//将SR[s..t]平分为SR[s..m]和SR[m+1..t] 
		MSort(SR, R, s, m);					//递归地将SR[s..m]归并为有序的R[s..m] 
		MSort(SR, R, m+1, t);				//递归地将SR[m+1..t]归并为有序的R[m+1..t] 
		Merge(R, TR, s, m, t);				//将R[s..m]和R[m+1..t]归并到TR[s..t] 
	}
}

//5.算法10.14:对顺序表L作归并排序。
void MergeSort(SqList_sort *L)
{	
	MSort((*L).r, (*L).r, 1, (*L).length);
}

int main(int argc, char *argv[])
{
	SqList_sort L;
	
	CreateSortList(&L);

	printf("将关键字按递增顺序排列...\n");
	MergeSort(&L); 
	Traverse(L);
	printf("\n");
		
	return 0;
}
发布了674 篇原创文章 · 获赞 103 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/103973823