【数据结构(39)】8.5 归并排序

基本思想

  • 将两个或两个以上的有序子序列归并为一个有序序列。
  • 在内部排序中,通常采用的是2-路归并排序
    • 即:将两个位置相邻的有序子序列 R[l…m] 和 R[m+1…n] 归并为一个有序序列 R[l…n]。

举个例子

  • 假设初始关键字序列为:{48,34,60,80,75,12,26,48*}。
    • 初始序列有 n 个记录,则可看成是 n 个有序的子序列,每个子序列的长度为 1,然后两两归并,得到 n/2 个长度为 2 或 1 的有序子序列;
    • 再两两归并,……如此重复,直到得到一个长度为 n 的有序序列位置。

在这里插入图片描述

  • 归并排序完成之后的图形很像一棵倒着的树,所以将这种树称为归并树
  • 归并排序需要的趟数就是树的高度,树的高度则是 nlog₂n,也就是说整个归并排序仅需要 nlog₂n 趟。

1. 相邻两个有序子序列的归并

算法步骤

  • 假设两个有序表存放在同一数组中相邻的位置上:R[low…mid] 和 R[mid+1…high],每次分别从两个表中取出一个记录进行关键字的比较,将较小者放入 T[low…high] 中,重复此过程,直到其中一个表为空,最后将另一个非空表余下的部分直接复制到 T 中。

举个例子

  1. 用两个指针分别代表元素的下标,
    • 比较一下当前两个子序列的第一个元素,谁小就将谁放到新的数组当中。
    • 将值存进新数组以后,将指向被拿出元素的数组下标的指针往后移。

在这里插入图片描述
在这里插入图片描述

  1. 再比较两个指针指向的元素,小的存进新数组,然后将指针后移。

在这里插入图片描述

  1. 重复上述步骤,直到其中一个子序列为空为止,最后将另一个非空表中剩下的元素直接搬到新数组中。

在这里插入图片描述

算法描述

//将有序表R[low...mid]和R[mid+1...high]归并为有序表T[low...high]
void Merge(RedType R[],RedType T[],int low,int mid,int high)
{
		int i = low;
		int j = mid + 1;
		int k = low;

		while(i <= mid && j <= high)//将R中记录由小到大并入T中
		{
				if(R[i].key <= R[j].key)
				{
						T[k++] = R[i++];
				}
				else 
				{
					T[K++] = R[j++];
				}
		}
		while(i <= mid)//将剩余的R[i...mid]的元素复制到T中
		{
				T[k++] = R[i++];
		}
		while(j <= high)//将剩余的R[j...high]的元素复制到T中
		{
				T[k++] = R[[j++];
		}		
}

2. 归并排序算法

算法步骤

  • 2路归并排序将 R[low…high] 中的记录归并排序后放入 T[low…high] 中。当序列长度等于1时,归并结束,否则:
    1. 将当前序列一分为二,求出分裂点 mid = (low +high) / 2;
    2. 对左子序列 R[low…mid] 递归,进行归并排序,将结果放入新数组 S[low…mid] 中;
    3. 对右子序列 R[mid + 1…high] 递归,进行归并排序,结果放入新数组 S[mid + 1…high]中;
    4. 调用函数 Merge,将有序的两个子序列 S[low…mid] 和 S[mid +1…high] 归并为一个有序的序列 T[low…high]。

算法描述

//将R[low...ghig]归并排序后放入T[low...high]中
void MSort(RedType R[],RedType T[],int low,int high)
{
		if(low == high)
		{
				T[low] = R[low];
		}
		else
		{
				mid = (low + high) / 2;//将当前序列一分为二,求出分裂点 mid
				MSort(R,S,low,mid);//对子序列R[low...mid]递归归并排序,将结果放入S[low...mid]中
				MSort(R,s,mid+1,high);//对子序列R[mid...highg]递归归并排序,将结果放入S[mid+1...high]中
				Merge(S,T,low,mid,high);//将S[low...mid]和S[mid+1...high]归并到T[low...high]
		}
}

//对顺序表L做归并排序
void MergeSort(SqList &L)
{
		MSort(L.r,L.r,1,L.length);
}

3. 归并排序算法分析

  • 时间效率O(nlog₂n)
    • 当有 n 个记录时,需要进行 log₂n 趟归并排序,每一趟归并,其关键字比较次数不超过 n,元素移动次数都是 n,因此,归并排序的时间复杂度为 O(nlog₂n)。
  • 空间效率O(n)
    • 因为需要一个与原始序列同样大小的辅助序列(R1)。这正是此算法的缺点。
  • 稳定性稳定
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值