如何判断单链表有环及正确性证明

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/mucaoyx/article/details/81395782

双指针判断单链表是否有环的正确性证明

​问题:给你一个单链表,需要找到一个方法进行判断是否有环的存在。
这篇文章主要证明一下,为什么存在环的情况下两个指针(slow和fast指针)就一定会相遇。

双指针判断单链表是否有环

​使用两个slow, fast指针从头开始扫描链表。指针slow 每次走1步,指针fast每次走2步。如果存在环,则指针slow、fast会相遇;如果不存在环,指针fast遇到NULL退出。

其实就是所谓的追及相遇问题:

这里写图片描述

证明存在环就会导致两个指针(slow和fast指针)一定相遇。

现在,我把情况还原到完整的环中,看看具体发生的情况到底是什么?
首先看下面的图,图中的单链表是有环的。
在这里插入图片描述

图1. 有环的单链表

在这里插入图片描述

图2. 步骤一

在这里插入图片描述

图3. 步骤二

在这里插入图片描述

图4. 步骤三

从图4可以看出,经过两次移动,fast指针刚好进入环,指向node4节点,而slow指针才移动到node2节点。

在这里插入图片描述

图5. 步骤四

在这里插入图片描述

图6. 步骤五
从图6可以看到,当slow指针移动到node4节点,即刚进入环时,fast指针已经移动到node8节点了。

在这里插入图片描述

图7. 步骤六

从图7中看到,非常的巧,slow指针进入环后,向前移动了一次就和fast指针相遇了。

将上述的过程一般化。
首先可以肯定得是fast指针一定是先进入到环中的,随后slow指针才会进入到环中,可能slow进入环中时,fast指针已经在环里面循环很多圈了,这都没关系,我们只关注slow指针进入环时,fast指针与slow指针的相对位置。
在这里插入图片描述

图8. 泛化

链表除头节点外,所有的节点都统一编号,进入环的节点是node k,图中只是标注了编号。整个环由k节点,k+1节点,…k+n节点构成,一共是(n+1)个节点。
最开始的时候slow指针和fast指针都指向头节点,然后两个指针同时移动k次:
(1) slow指针每次移动一个节点,到达k号节点,刚好是进入环的节点。
(2) fast节点每次移动二个节点,通过2*k个节点,到达k+x号节点,处于环中。
这个x可以计算出来,如下所示:

x=2kk%n+1 x =(2*k -k)\%(n+1)

下面进行验证一下。对于图6而言,k=4,n=4,所以x=4,所以当slow指向node4时,fast指针应该指向node(k+x)就是node8,可以看到图6已经验证了这个结论。

下面计算一下slow指向k节点时,fast与slow地相对距离m。

m=nx+1=n+1(2kk)%(n+1)=n+1k%(n+1) \begin{aligned} m=&n-x+1\\ =&n+1-(2*k -k)\%(n+1) \\ =&n+1 - k\%(n+1) \end{aligned}

m满足:

m<(n+1) m<(n+1)

也就是说保持slow指针不动,fast指针再向前走m个节点就可以和slow指针相遇。
由于slow指针向前移动一个节点,fast指针就会向前移动两个节点,所以同时再移动m次就可以相遇了。下面来给出证明。
由上面的假设可知,当slow进入环时,即指向node k节点时,fast指针与slow指针的相对距离是m,也就是此时保持slow不动,fast再向前移动m个节点就可以和slow相遇。
那么,现在slow和fast同时移动m次。slow节点会到达的节点为:
k+m k+m
fast节点会到达:

k+(x+2m)%(n+1)=k+((2kk)%(n+1)+2m)%(n+1)=k+(k%(n+1)+2((n+1)k%(n+1)))%(n+1)=k+(k%(n+1)+2(n+1)2k%(n+1))%(n+1)=k+(2(n+1)k%(n+1))%(n+1)=k+(n+1k%(n+1))%(n+1)+(n+1)%(n+1)=k+(n+1k%(n+1))%(n+1) \begin{aligned} k+(x+2*m)\%(n+1)=&k+((2*k -k )\%(n+1) + 2*m)\%(n+1) \\ =&k+(k\%(n+1)+ 2*((n+1) - k\%(n+1)))\%(n+1) \\ =&k+(k\%(n+1) + 2*(n+1) - 2*k\%(n+1))\%(n+1) \\ =&k+(2*(n+1)-k\%(n+1))\%(n+1) \\ =&k+(n+1 - k\%(n+1))\%(n+1)+(n+1)\%(n+1) \\ =&k+(n+1 - k\%(n+1))\%(n+1) \end{aligned}
下面进行化简与推导:
m=n+1k%(n+1)k+(x+2m)%(n+1)=k+m%(n+1)m<(n+1)m%(n+1)=mk+(x+2m)%(n+1)=k+m \begin{aligned} \because \quad &m=n+1-k\%(n+1) \\ \therefore \quad &k+(x+2*m)\%(n+1)=k+m\%(n+1) \\ \because \quad &m<(n+1) \\ \therefore \quad &m\%(n+1)=m \\ \therefore \quad &k+(x+2*m)\%(n+1)=k+m \end{aligned}

所以slow指针进入到环时,fast和slow指针共同再移动m次就可以在k+m节点相遇了。

综上所述:

slow指针进入环后,只要再走m步(fast落后slow指针的节点数)就一定会和fast指针相遇。slow指针进入环后,假设fast指针再往前走m个节点就会到达当前slow指针的位置,那么当slow指针和fast指针同时移动的时候,slow指针每向前移动一个节点,fast指针就会向前移动两个节点,fast与slow之间的距离就会缩短一个,所以当移动m步之后,fast指针就会和slow指针相遇。

如果证明有误,欢迎留言指正~

参考资料:检测单链表是否有环

展开阅读全文

没有更多推荐了,返回首页