(十)1.4_归并排序

在这里插入图片描述

一.相关概念

  归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
在这里插入图片描述
  线性表在合并时用的是有序线性表快速合并的算法,即要合并两个有序递减线性表La,Lb,则需创建一个新的线性表Lc,循环遍历La,Lb中的元素,哪个元素更小就先存入Lc中.相必大家都知道这个简单算法,不知道的可以看我的之前一篇博客:线性表求并集

  线性表在分解时简单的算法用的就是递归,但是递归算法实用性很差,数据量大一些很容易就爆栈,所以我要在这里教大家非递归二路归并排序算法的实现



二.思路分析

  1.首先如何分解?我们用非递归实现就是依次进行1 1 合并,2 2合并, 4 4 合并, 8 8 合并,16 16 合并…所以我们用一个循环就可以实现(d*=2),第一趟以2个元素为一对要合并的线性表(d=2,一个线性表1个元素),第二趟4个一对(d=4,一个线性表2个元素),.第三趟8个一对(d=8,一个线性表4个元素),每趟过程中对每对进行有序线性表快速合并(每对看作是有两个线性表)

  2.既然是进行有序线性表快速合并,则需要创建一个和原线性表L同等大小的线性表list
  第一趟2个一对,每对内进行合并,也就是1 1 合并,合并到辅助线性表list
  第二趟4个一对,每对内进行合并,也就是2 2 合并,这时上一次合并完成的元素存储在线性表list中,所以我们以原线性表L.elem作为辅助线性表,把元素从list合并到L.elem中,
  第三趟…
  就是这样L.elem和list轮流作为辅助线性表,直到一对中的元素大于总元素数量的两倍(d>2L.length),排序完成.
  (为啥是d>2
L.length?举个例子,假如元素数量9个,那么当一对8个时,线性表中就会有 4 4 合并,和1 0 合并,并没有完成9个元素的合并,需要进行16个一对的合并,就会有8 1 合并,所以d>2*L.length就是为了避免这种元素数量非2的整指数次方的情况)

  3.每趟进行分对后,一对内有两组线性表,我们要对它们进行遍历排序合并,所以要分割成两组,大部分是对半分,但是并不是每对的元素数量都等于增量,比如总元素数量是9个,那么当以4个元素一对时,就会是2 2合并 2 2 合并 1 0合并,不全是2个一组,所以我们把一对线性表分割成两组线性表进行遍历时,并不都是对半分,要考虑在这种元素数量非2的整指数次方的情况
  (我把每组线性表的起点和上限都进行了计算和判断,然后在起点和上限范围中进行遍历,就可以保证遍历位置不会出错,具体看代码)

  4.排序完成后有序序列存储在哪个线性表?这个简单,我们用变量count记录合并趟数,如果是奇数就在list中,如果是偶数就在L.elem中,然后保存和释放对应的线性表就行了



三.代码实现

注意:顺序表中零单元不用,从索引1开始存储元素

//归并排序(排列为递增序列)
void MergeSort(SqList &L)
{   
	ElemType *list=(ElemType*)malloc(sizeof(ElemType)*(L.length+1));  //新建辅助顺序表 
	ElemType *p=NULL,*q=NULL;
	int count,d,pos1,pos2,pos,l,r,t1,t2;       //count排序趟数,d组距,pos1第一组元素遍历位置,pos2第二组元素遍历位置,pos合并组存储位置
	for(count=1,d=2;d<=2*L.length;d*=2,count++)//l第一组左端,r第二组右端,t1第一组上限,t2第二组上限 
	{   //L.elem和list轮流作为辅助线性表  
		p=(count%2==1)?list:L.elem;          //p为归并存储线性表 
		q=(count%2==1)?L.elem:list;			 //q线性表为要进行归并的线性表
		for(l=1,r=l+d-1;l<=L.length;l+=d,r=l+d-1)
		{
			pos1=l;        //第一组线性表起点 
			t1=(l+d/2-1)<L.length?(l+d/2-1):L.length;  //第一组线性表上限 
			pos2=1+t1;    //第二组线性表起点 
			t2=r<L.length?r:L.length;                  //第二组线性表上限			
			pos=l;    //合并组线性表起点 
		    while(pos1<=t1&&pos2<=t2)    //将q中更小的元素先并入p中 
			{
				if(q[pos1]<=q[pos2])
					p[pos++]=q[pos1++];
				else
					p[pos++]=q[pos2++];	
			}	
			while(pos1<=t1)
				p[pos++]=q[pos1++];        //将剩余的q[pos1..t1]复制到p 		
			while(pos2<=t2)
				p[pos++]=q[pos2++];       //将剩余的q[pos2..t2]复制到p				    	
		}
	}
	L.elem=p;  //归并完成的线性表(p可能是原来的L.elem线性表,也可能是list线性表) 
	free(q);   //释放辅助线性表内存(q可能是原来的L.elem线性表,也可能是list线性表) 		
}

操作结果
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值