分治策略—归并排序

     归并排序很好的体现了分治策略的思想,即将问题分解成同样但事实规模更小的子问题。比如说这里的归并排序,就是有序子列的并归。

如上图 将两个子序列合并到一个temp 数组(这里是暂存的作用),需要三个指针Aptr 与 Bptr 相比较 小的插入暂存数组Cptr , 随着向后移动。代码如下

void Merge(ElementType A[], ElementType TmpA[], int L, int R, int RightEnd) { /* 将有序的A[L]~A[R-1]和A[R]~A[RightEnd]归并成一个有序序列 */  int LeftEnd, NumElements, Tmp;  int i;
 LeftEnd = R - 1; /* 左边终点位置 */  Tmp = L;         /* 有序序列的起始位置 */  NumElements = RightEnd - L + 1;
 while (L <= LeftEnd && R <= RightEnd) {   if (A[L] <= A[R])    TmpA[Tmp++] = A[L++]; /* 将左边元素复制到TmpA */   else    TmpA[Tmp++] = A[R++]; /* 将右边元素复制到TmpA */  }
 while (L <= LeftEnd)   TmpA[Tmp++] = A[L++]; /* 直接复制左边剩下的 */  while (R <= RightEnd)   TmpA[Tmp++] = A[R++]; /* 直接复制右边剩下的 */
 for (i = 0; i < NumElements; i++, RightEnd--)   A[RightEnd] = TmpA[RightEnd]; /* 将有序的TmpA[]复制回A[] */ }

后面分为递归的方式与非递归。

   我们先来看一下递归的算法:

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 );  /* 合并两段有序序列 */ 
	}
}

void MergeSort(ElementType A[], int N )
{ /* 归并排序 */
	ElementType *TmpA;
	TmpA  = (ElementType *)malloc(N * sizeof(ElementType));

	if (TmpA  != NULL ) {
		Msort(A, TmpA, 0, N - 1);
		free(TmpA );
	}
	else printf("空间不足");
}

递归的算法很直观的表示了分治策略。 即将规模化小。在MergeSort里面,定义了一个方法的接口,用户只需要传入,排序的数组,tempA数组的分配是在次方法里面进行的。

调用过程可以如下图表示

在接下来我们看看非递归的方式。即用循环来代替递归调用。

代码如下:


先看原理图:

这里需要额外的空间来暂存排序结果。但是实际上只要一个tempA数组就好,tempA与A数组之间相互copy 来实现暂存。只是在最后要copy到A数组中罢了。

在Marge_Sort中length  = 1,即表示最小的有序子序列是1个数字。这个很好理解。Marge_Pass 就是将数组按 length的长度跳跃扫描一遍。用marge来合并成有序的上一序列。Marge_Sort 有两次次 Marge_Pass的调用。这是为了将tempA,中数组赋值个给A。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值