• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

无信不立

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【数据结构和算法】证明链表有环的算法正确性

转载至博客: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=(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 = ​n-x+1

   = n+ 1- (2*k-k)%(n+1)

   = n+1- k%/(n+1)

m满足:

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

 

fast节点会到达:

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)​ 

 

下面进行化简与推导:

∵ m=n+1−k%(n+1)

∴ k+(x+2∗m)%(n+1)=k+m%(n+1)

∵ m<(n+1)

∴ m%(n+1)=m

∴​ k+(x+2*m)%(n+1)=k+m

 

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

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

 

===============证明思路==============

1、先通过一个例子进行说明思路。

2、将例子进行泛化,用参数表现。

3、分析问题,转化成数学的追及问题。

4、求证,当slow进入环后,fast与其的相对位置,以及fast和slow相遇的条件。证明两者移动后的位置,是否相等。

===============链表有环的算法========

package com.spring.test.service.algorithm.problem;

/**
 * @date 8:22 PM 2019/6/16
 */
public class LinkedListHasARing {


    /**
     * 判断Node是否有环
     *
     * @param node
     * @return
     */
    public static boolean isHasARing(Node node) {
        if (node == null) {
            return false;
        }
        Node slow = node;
        Node fast = node;
        while (fast != null && fast.next != null) {
            //循环不变式,如果最快的节点不为空,且它的下一个节点也不为空,则说明链表还没有到尾端
            //移动快的节点,如果到尾端了,还没有跳出循环,说明无环

            //slow移动一个节点
            slow = slow.next;
            //fast移动两个节点
            fast = fast.next.next;
            if (slow == fast) {
                //如果fast节点等于next节点,则证明链表有环
                return true;
            }
        }
        return false;
    }
}

/**
 * 链表节点
 */
class Node {
    String obj;
    Node next;
}
View Code

 



​

 

posted on 2019-06-16 20:11  无信不立  阅读(508)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3