合并有序表

问题 :

●假设有两个有序表 LA和LB , 将他们合并成一个有序表LC

●要求不破坏原有的表 LA和 LB

LA  : 1 , 3 , 5

LB : 2,4,8,20

构思:

把这两个表, 合成一个有序表 , 不是简简单单吗 ? 

就算是把他们先遍历不按顺序插入到表 C里面 , 然后再排序 ,就行了,

这个的确是最笨的办法 , 但是也能完成 

题目上 ,给出的是这两个表都是有序表  , 所以就省去了 ,我们遍历所有节点排序的麻烦 , 那我们

也不能拿一个表进行强行插入, 题目上也不允许,

我们干脆假设 这两个列表是两幅卡片 , 我们都从第一张开始那,左手一直拿 A , 右手一直拿 B

对比这两个卡片 ,哪个小就先装到 LC ,装进去之后,如果是左手卡片小,就装到 Lc , 然后再拿一张A里面的卡片 ,再和右手对比 ,我们这样比较的前提是 ,这两个表里面的元素都是从小到大顺序排列的 ,

这样 LC 就不会出现需要插入的情况 ,如果一副卡片放完了,另一幅如果还有 ,那剩余的卡片一定是大的 ,直接放在 LC 后面就行了

至于我们用顺序表来存储LC ,还是用链表来存储LC, 基本思路还是一样的,操作有些许差别罢了


我们用这种交替的比较两个有序表 ,然后排序的好处是,空间复杂度低, 时间复杂度也低 ,

我们有的同学会有疑问, 难道交叉比较, 不会出现错乱吗? 

答案是不会的 ,因为这两个表本身就是有序表 , 然后我们插入Lc之前 , 会让两个列表中小的进行插入 , 然后后面该插入的元素, 因为是有序表,所以都大于前面的元素 . 这就保证了插入的有序性.

下面开始实操:

采用顺序表存放有序表时的归并算法:

我们要将两个有序表的元素进行比较, 就需要各有一个指针指向有序表 , 然后再进行比较 , 

两个指针比较, 小的元素插入到 LC 里面 , 插入完元素的指针向后移动 .

由于两个有序表的长度不同 , 所以交替插入有三种情况 :

●LA 和 LB 均未到达末尾时,泽其小优先尾插

●LB已经扫描插入完了, LA尚未扫描插入完 , 将其余元素插入到 Lc中

●LB尚未扫描插入完  , 将其余元素插入到 Lc中

我们先传入 LA 和 LB , 建立的LC

void UnionLIst(SqList *LA, SqList *LB , SqList *&LC){

然后,如何判断 LA和LB有没有扫描插入完呢?

我们是根据指针指向两个有序表元素的 , 所以比较指针遍历的元素个数 和 表长度 就可以得出那个表有没有遍历完

所以,先定义指向两个列表的指针

int i = 0 , j=0 , k=0;  //LA 插入的数组位序 ,LB插入的数组位序 , LC插入的坐标位序


因为列表是数组 , 所以次指针非彼指针 , 这是比较元素的位序

申请 LC 的空间 

LC = (SqList *)malloc(sizeof(SqList));

所以我们要进行上面三种情况的处理 :

//LA 和 LB 均未到达末尾时,泽其小优先尾插

while(i<LA->length && j<LB->length){  交替插入元素}

//LB已经扫描插入完了, LA尚未扫描插入完 , 将其余元素插入到 Lc中

while(i<LA->length){ 把A中剩余的元素全插入到LC }

//LB尚未扫描插入完  , 将其余元素插入到 Lc中

while(i<LB->length){ 把B中剩余的元素全插入到LC }

然后就把C的长度更新一下就行了\

开始代码实现:

void UnionList(SqList *LA , SqList *LB , SqList *&LC)
{
	int i=0;	//LA的坐标位序
	int j=0;	//LB的坐标位序
	int k=0;	//LC的坐标位序
	LC = (SqList *)malloc(sizeof(SqList));  //为表C分配空间
	//LA和LB 均未到达末尾 ,选择小的加入LC
	while(i<LA->length && j<LB->length)
	{
		if(LA->data[i] < LB ->data[j])
		{
			LC->data[k] = LA ->data[i];
			i++;	//相应的LA指针也向后移动
			k++;	//元素加一,位序后移
		}
		else		//LA->data[i]  >= LB->data[j] ,交替比较无所谓的,反正小的会在前面 
		{
			LC->data[k] = LB->data[j];
			j++;	//相应的LB指针也向后移动
			k++;	//元素加一,位序后移
		}
	
	}
	//下面两步最多进行一步:

	//经过上一轮循环插入,LB已经扫描插入完了, LA尚未扫描插入完 , 将LA其余元素插入到 Lc中
	while(i<LA->length)
	{
		LC->data[k] = LA->data[i];
		k++;
		i++;	//相应的LA指针向后移动
	}
	//经过第一轮循环插入,,LA已经扫描插入完了, LB尚未扫描插入完 , 将LB其余元素插入到 Lc中
	while(j<LB-length)
	{
		LC->data[k] = LB->data[j];
		j++;	//相应的LB指针向后移动
		k++;	//元素加一,位序后移
	}
}

采用单链表存放有序表时的归并算法:

和上面那个问题一样 , 同样的思路 ,不多赘述了 ,区别就是 遍历两个链表的指针不一样 ,插入的赋值操作不一样 , 其他的算法思路都是一样的, 下面直接上代码:

//传入单链表LA,LB,和创建的链表LC
void UnionList1(LinkList *LA, LinkList*LB , LinkList *&LC)
{
	//定义指向LA和LB的指针 
	LinkList *pa = LA ->next, *pb = LB->next;
	//构建链表C的头结点 , 我们把LA和LB的新元素插入到LC 需要利用尾插法,
	//尾插法需要尾指针定位到LC的最后一个节点
	LinkList *r; //指向LC的尾结点的指针
	LinkList *s; //向LC的新节点的指针
	LC = (LinkList *)malloc(sizeof(LinkList));
	//刚开始,尾指针指向LC的头结点,LC的尾指针置空	
	r=Lc;
	LC->next = NULL;
	//下面开始插入:
	//LA 和 LB 均未到达末尾时,泽其小优先尾插
	while(pa!=NULL && pb !=NULL)
	{
		//为了不破坏LA和LB,要另起灶炉,构建新节点
		s = (LinkList *)malloc(sizeof(LinkList));
		//如果指向LA的指针的数据小于LB的指针数据, 就把La的指针pa 数据赋值给新节点数据
		if(pa->data < pb -> data)
		{
			s->data = pa ->data;
			//LA指针后移
			pa = pa ->next;			
			//对LC进行尾插法
			r ->next=s;		
			r=s;
		}
		else	//同理:
		{
			s->data = pb->data;
			//LB指针后移
			pb = pb->next;
			//对LC进行尾插法
			r ->next=s;
			r=s;
		}

	}
	//经过上一步的交替插入,要么两个表交替插入完了,要么是下面两者之一
	//LB已经扫描插入完了, LA尚未扫描插入完 , 将其余元素插入到 Lc中
	while(pa!=NULL)
	{
		s = (LinkList *)malloc(sizeof(LinkList));
		//LA指针送给的数据指向新节点
		s->data = pa->data;
		//下面开始尾插法
		r->next = s;
		r = s;
		//LA指针后移
		pa = pa ->next;
	}
	//LA已经扫描插入完了, LB尚未扫描插入完 , 将其余元素插入到 Lc中
	while(pb!=NULL)
	{
		s = (LinkList *)malloc(sizeof(LinkList));
		//LA指针送给的数据指向新节点
		s->data = pb->data;
		//下面开始尾插法
		r->next = s;
		r = s;
		//LB指针后移
		pb = pb ->next;
	}
    s->next = NULL;
}

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值