【数据结构】 合并两个非递减有序单链表为一个A-B的非递减有序单链表

【数据结构】 合并两个非递减有序单链表为一个A-B的非递减有序单链表

题目

  • 实现两个单链表La和Lb的相减链表LC,LC的元素为LA中有但LB中没有的元素。LA和LB都为非递减有序链表

分析

  • LC是LA和LB的相减链表,即LC= LA-LB,即LC里的元素是在LA的基础减去LB里也有的元素。比如LA的元素为1,3,5,7,9,LB的元素为2,4,5,7,9,那么LC的元素为1,3 。
    蓝色部分即为A-B

解题思路

  • 再重复一下我们的分析: LC是LA和LA的相减链表,即LC里的元素是在LA的基础减去LB里也有的元素。
  • 所以思路就是:
    • 首先把LC指向LA。(“在LA的基础上”)
    • 遍历LA和LB链表,找到A∩B的元素,并删除LA相应的元素。(“减去LB里也有的元素”)
  • 一般我们会先遍历LA,对于每个LA的元素都遍历一次LB,看是否有相等的元素删去。这样做法的时间复杂度是O(n2)。但由于LA和LB都是非递减有序的,我们可以优化一下,改成O(n)的做法。
优化
  • 假设p为遍历LA的指针,q为遍历LB的指针。
  • 我们可以发现,由于我们整个操作都是在LA的基础上进行元素的删除,所以LA的每一个元素是必须要遍历一遍的。但由于LB是非递减序列,我们可以通过与LA元素的比较来确定q指针的位置:
  1. p->data < q->data, 此时LA的元素 < LB的元素, 对于LA的下一个元素m, 此时LB的元素更大,不能确定LB前面有没有比m更小的数,所以应返回LB开头重新遍历。即q = LB->next。【LA:2( p), 3,5,9,LB:1,3,4(q),7】
  2. p->data > q->data,此时LA的元素 > LB的元素,对于LA的下一个元素m,此时LB的元素偏小,所以继续往后遍历LB即可。即q = q->next。【LA:2,3,5( p),9,LB:1,3,4(q),7】
  3. p->data == q->data,此时LA的元素 ==LB的元素, 将LA中的结点删掉,继续遍历LA,LB。即p = p->next, q = q->next。【LA:2,3( p),5,9,LB:1,3(q),4,7】
难点
  • 可以发现,只有当p->data == q->data时,p才会往后走。
  • 后来写代码的时候发现出现死循环,因为LA走的还不够。当[ LA:2,3,5( p),7,9,LB:1,3,4(q),7] 时,我们会先执行上面的第2步,然后LB继续遍历,变成[ LA:2,3,5( p),7,9,LB:1,3,4,7(q) ], 此时程序执行第1步,LB从头开始遍历,此后一直执行第2步,直到[ LA:2,3,5( p),7,9,LB:1,3,4,7(q) ] ,陷入死循环。
  • 跳出死循环的方法是让p往前走一步。p往前走一步的前提是,当前p比q大且比q的下一个元素小,即p必然是在LC中的,可以往前走一步。

代码:

//初始化:pre指向LA当前结点的前一个结点,r指向LA当前结点的下一个结点。
	while(p && q){
   	//遍历LA 
		r = p->next;
		if(p->data < q->data){
   	//A<B
			q = LB->next;
		}
		else if(p->data > q->data){
   	//A>B
				q = q->next;
				//难点
				if(p->data < q->data){
   //A<B的下一个,即A在两者间 
					pre = p;
					p = p->next;
				}
  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值