如何判断单链表中有环及证明过程

问题:

1.如何判断单链表里面是否有环?

算法的思想是设定两个指针p, q,其中p每次向前移动一步,q每次向前移动两步。那么如果单链表存在环,则p和q相遇;否则q将首先遇到null。
这里主要理解一个问题,就是为什么当单链表存在环时,p和q一定会相遇呢?

假定单链表的长度为n,并且该单链表是环状的,那么第i次迭代时,p指向元素i mod n,q指向2i mod n。因此当i≡2i(mod
n)时,p与q相遇。而i≡2i(mod n) => (2i - i) mod n = 0 => i mod n = 0 =>
当i=n时,p与q相遇。这里一个简单的理解是,p和q同时在操场跑步,其中q的速度是p的两倍,当他们两个同时出发时,p跑一圈到达起点,而q此时也刚
好跑完两圈到达起点。
那么当p与q起点不同呢?假定第i次迭代时p指向元素i mod n,q指向k+2i mod n,其中0<k<n。那么i≡(2i+k)(mod n) => (i+k) mod n = 0 => 当i=n-k时,p与q相遇。

这里的关键是理解,其实,快指针和慢指针虽然一开始不在环里,但是当他们都进入环里的时候,其实这个问题的模型相当于两个指针在环里起点不同的模型。

懂了这点,后续很多证明都好理解了。

扩展阅读:

推广:

1. 如果两个指针的速度不一样,比如p,q,( 0<p<q)二者满足什么样的关系,可以使得两者肯定交与一个节点?

Sp(i) = pi

Sq(i) = k + qi

如果两个要相交于一个节点,则 Sp(i) = Sq(i) =>  (pi) mod n = ( k+ qi ) mod n =>[ (q -p)i + k ]  mod n =0

=>  (q-p)i + k  = Nn [N 为自然数]

=>  i = (Nn -k) /(p-q)

i取自然数,则当 p,q满足上面等式 即 存在一个自然数N,可以满足Nn -k 是 p - q 的倍数时,保证两者相交。

特例:如果q 是p 的步长的两倍,都从同一个起点开始,即 q = 2p , k =0, 那么等式变为: Nn=i: 即可以理解为,当第i次迭代时,i是圈的整数倍时,两者都可以交,交点就是为起点。

2.如何判断单链表的环的长度?

这个比较简单,知道q 已经进入到环里,保存该位置。然后由该位置遍历,当再次碰到该q 位置即可,所迭代的次数就是环的长度。

3. 如何找到链表中第一个在环里的节点?

假设链表长度是L,前半部分长度为k-1,那么第一个再环里的节点是k,环的长度是 n, 那么当q=2p时,
什么时候第一次相交呢?当q指针走到第k个节点时,q指针已经在环的第 k mod n 的位置。即p和q
相差k个元素,从不同的起点开始,则相交的位置为 n-k, 则有了下面的图:

从图上可以明显看到,当p从交点的位置(n-k) ,向前遍历k个节点就到到达环的第一个几点,节点k.

算法就很简单: 一个指针从p和q 中的第一次相交的位置起(n-k),另外一个指针从链表头开始遍历,其交点就是链表中第一个在环里的交点。

时间: 2024-10-29 19:06:19

如何判断单链表中有环及证明过程的相关文章

判断单链表里面有没有环

原文链接:http://www.cnblogs.com/zhyg6516/archive/2011/03/29/1998831.html 这题目还是挺有意思的. 题目:0.如何判断单链表里面是否有环? 算法的思想是设定两个指针p, q,其中p每次向前移动一步,q每次向前移动两步.那么如果单链表存在环,则p和q相遇:否则q将首先遇到null. 这里主要理解一个问题,就是为什么当单链表存在环时,p和q一定会相遇呢? 假定单链表的长度为n,并且该单链表是环状的,那么第i次迭代时,p指向元素i mod

如果单链表有环,求环的起始位置

问题:如果单链表中存在环,求环的起始位置 解:在上篇文章中,利用追逐法判断一个单链表是否存在环.求环的起始位置,需要求解单链表的长度和环的长度的关系.如果确定了单链表的长度和环的长度的关系,那么环的起始位置就呼之欲出了. 在判断单链表中有两个指针P和q,p每次前进两步,q每次前进一步,p的速度是q的两倍.设单链表的长度为L,环的长度为R,链表起点到环起点的距离为X,当p和q相遇时,慢指针总共走了S步,在环内总共走了a步,快指针总共走了2S步,此时满足:2S=S+n*R,所以S=n*R. S=X+

判断单链表是否存在环及寻找环的入口点

一.判断单链表是否存在环 这个问题有很多方法,最容易想到的就是记录每个节点记录的次数.这里也介绍的是另一种简单而常见的方法 快慢指针法: 定义两个指针slow, fast.slow指针一次走1个结点,fast指针一次走2个结点.如果链表中有环,那么慢指针一定会再某一个时刻追上快指针(slow == fast).如果没有环,则快指针会第一个走到NULL 1 int has_cycle(node *head) { 2 if (head == NULL) return false; 3 node* f

如何判断单链表是否存在环

原文:http://blog.csdn.net/liuxialong/article/details/6555850 如何判断单链表是否存在环 给定一个单链表,只给出头指针h: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针slow.fast,从头指针开始,每次分别前进1步.2步.如存在环,则两者相遇:如不存在环,fast遇到NULL退出. 2.对于问题2,记录下问题1的碰撞点p,

如何判断单链表是否存在环 &amp; 判断两链表是否相交

给定一个单链表,只给出头指针h: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针slow.fast,从头指针开始,每次分别前进1步.2步.如存在环,则两者相遇:如不存在环,fast遇到NULL退出. 2.对于问题2,记录下问题1的碰撞点p,slow.fast从该点开始,再次碰撞所走过的操作数就是环的长度s. 3.问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分

判断单链表是否有环及寻找环的入口

一.判断单链表是否有环 1.遍历链表 遍历链表,将已经访问过的结点,设置为已访问,如果访问同一结点两次,则说明有环,时间O(n),空间O(n). 2.链表反转 遍历链表,将访问的结点指针反向.如果存在环,反转后next指向原链表头,但链表反转会破坏链表的结构,反转需要注意缓存当前结点的下一结点,时间O(n),空间(1). 3.快慢指针 设置快慢两个指针fast和slow,两个指针都链表头开始,fast每次移动2步,slow为1步.如果存在环,则fast先进入环,slow后进入环,最后两者在环中相

数据结构和算法设计专题之---判断单链表中是否有环,环的长度,环的入口节点

题目: 给定一个单链表,只给出头指针head: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针slow.fast,从头指针开始,每次分别前进1步.2步.如存在环,则两者相遇:如不存在环,fast遇到NULL退出. 2.对于问题2,记录下问题1的碰撞点p,slow.fast从该点开始,再次碰撞所走过的操作数就是环的长度s. 3.问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的

11.判断单链表是否有环

判断单链表是否有环:   这里也是用到两个指针,如果一个链表有环,那么用一个指针去遍历,是永远走不到头的.   因此,我们用两个指针去遍历:first指针每次走一步,second指针每次走两步,如果first指针和second指针相遇,说明有环.时间复杂度为O (n). 方法 // 方法:检测单链表是否有环 public boolean hasCycle(Node head) { if (head == null) { return false; } Node first = head; Nod

判断单链表是否有环相关问题(转载加总结)

给定一个单链表,只给出头指针h: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针slow.fast,从头指针开始,每次分别前进1步.2步.如存在环,则两者相遇:如不存在环,fast遇到NULL退出. 2.对于问题2,记录下问题1的碰撞点p,slow.fast从该点开始,再次碰撞所走过的操作数就是环的长度s. 3.问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分