【数据结构】 合并两个非递减有序单链表为一个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 。
解题思路
- 再重复一下我们的分析: 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指针的位置:
- 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】
- 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】
- 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;
}