且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

《编程之美》3.6判断链表是否相交之扩展:链表找环方法证明

更新时间:2022-08-12 16:55:20

先看看原题:《编程之美》3.6编程判断两个链表是否相交,原题假设两个链表不带环。

  为了防止剧透使得没看过原题目的读者丧失思考的乐趣,我把***的解法隐藏起来。由于这个问题本身的解答并不是本文的重点,扩展问题也采用这种形式呈现。

注:位于(*)符号之间的文字出自于:http://blog.csdn.net/v_july_v/article/details/6447013,作者v_JULY_v

《编程之美》3.6判断链表是否相交之扩展:链表找环方法证明解法

 

 扩展问题1:如果链表可能有环,上面的方法怎么调整?

《编程之美》3.6判断链表是否相交之扩展:链表找环方法证明扩展问题1解法

 

扩展问题2:如果必须要求出两个链表相交的第一个节点呢?

《编程之美》3.6判断链表是否相交之扩展:链表找环方法证明扩展问题2解法

 

相关问题:求链表倒数第k个结点

《编程之美》3.6判断链表是否相交之扩展:链表找环方法证明相关问题解法

 

  现在来看,遗留问题是:1.如何判断链表有环?2.如何找到链表环的入口?方法是有的,而且这个算法在3.11节程序改错的扩展问题有所提示。简单来说就是:

  对于问题1,指针p1、p2指向表头,每次循环p1指向后继,p2指向后继的后继;循环的结束条件是,p2后继为空(无环)或p1==p2(有环)。

   这个方法网上没有看到比较令我满意的解释,而《编程原本》(Elements of Programming)在第2章“变换及其轨道”中虽然有简单的说明,可当时看的时候也不是特别理解(就算现在理解了,这本书上讲得比较抽象,上面的说明放在这里只能让读者越看越糊涂),可能是悟性不够吧。一是不满足于用举例说明,二是觉得,如果是连续地移动,即像物体运动时位移和时间是连续的而不是这样离散的,当然会相遇;而二者都是离散的,如果每次都发生p2刚好越过p1的情况呢?下面用易于理解的方式证明,这个解法中如果有环,p1和p2必同时在停留在某个节点。

《编程之美》3.6判断链表是否相交之扩展:链表找环方法证明

  如左图,在任意时刻,p1和p2都在环上。由于p1每次向前1步,p2每次向前两步,用相对运动的观点来看,把p1看作静止,那么p2每次相对p1向前1步,二者在顺时针方向上的距离每经过一个时刻就减少1,直到变为0,也即二者恰好相遇。这样就证明了在离散情况下,对于有环链表,二者也是必然在某一时刻相遇在某个节点上的。

  沿着这个思路,继续求解问题2寻找环的入口问题。记环的总长度为R(即,环上有R个节点),并将上述的初始时刻选为p1第一次到达环入口的时刻,相遇时p1在环上位置x%R,p2在环位置[2*(L+x)-L]%R,

《编程之美》3.6判断链表是否相交之扩展:链表找环方法证明

  在相遇点,有(2L+2x-L)%R == x%R,即(L+2x)%R==x%R。根据同余的性质,(L+x)%R==0。

  此时把p1放回表头,p2的速度降为1。当p1走了L到达环的入口时,p2在环上的位置为(x+L)%R==0,这意味着p2回到了入口,且与p1相遇。并且由于之前p1不在环上,这是二者的在这一步操作后的第一次相遇,并且都在入口,这便找出了入口的位置。

  重述一遍寻找环存在和环入口的方法:

用两个指针p1、p2指向表头,每次循环时p1指向它的后继,p2指向它后继的后继。若p2的后继为NULL,表明链表没有环;否则有环且p1==p2时循环可以终止。此时为了寻找环的入口,将p1重新指向表头且仍然每次循环都指向后继,p2每次也指向后继。当p1与p2再次相等时,相等点就是环的入口。






本文转自五岳博客园博客,原文链接:www.cnblogs.com/wuyuegb2312/p/3183214.html,如需转载请自行联系原作者