判断一个链表是否有环以及环的位置入口
2014-10-16 16:41
701 查看
给定一个单链表,只给出头指针head(指向头节点):
1、如何判断是否存在环?
2、如何知道环的长度?
3、如何找出环的连接点在哪里?
4、带环链表的长度是多少?
5、如何判断两个链表相交?
1,算法的思想是设定两个指针p,
q,其中p每次向前移动一步,q每次向前移动两步。那么如果单链表存在环,则p和q相遇;否则q将首先遇到null。
方法一:
(1)用两个指针p1和p2分别指向表头结点,即p1=p2=head
(2)p1和p2分别采用1和2作为步长遍历该链表。(注意,p2应该检查当前结点的下一个结点是否为NULL)
(3)如果p2遇到了NULL,则证明该链表没有环;若p1和p2在某时刻指向同一结点,则说明该链表有环
方法二:
(a)p从表头结点开始以1为步长遍历表,边遍历边将表反向
(b)如果p遇到NULL,则说明表没有环
(c)如果p最后等于head,则说明表有环,且记此时p所经过的表的结点数为l(l=2l1+c,l1和c的定义见方法一)
(d)p再从表头结点开始以1为步长遍历表,边遍历边反向,当遍历到l/2时,停止,设两个指针p1,p2均指向当前结点,然后分别从两个方向同时以1为步长遍历表(其中一个需要边遍历,边反向链表),当他们第相遇时,当前结点即为环头结点。且此时链表还原成原来的链表。
用两个指针来遍历这个单向链表,第一个指针p1,每次走一步;第二个指针p2,每次走两步;当p2 指针追上 p1的时候,就表明链表当中有环路了。
关于这个解法最形象的比喻就是在操场当中跑步,速度快的会把速度慢的扣圈.
可以证明,p2追赶上p1的时候,p1一定还没有走完一遍环路,p2也不会跨越p1多圈才追上.
我们可以从p2和p1的位置差距来证明,p2一定会赶上p1但是不会跳过p1的.
因为p2每次走2步,而p1走一步,所以他们之间的差距是一步一步的缩小,4,3,2,1,0 到0的时候就重合了.
根据这个方式,可以证明,p2每次走三步以上,并不总能加快检测的速度,反而有可能判别不出有环.
比如,在环的周长L是偶数的时候,初始p2和p1相差奇数的时候,p2每次走三步,就永远和p1不重合,因为他们之间的差距是: 5, 3 , 1,
L-1, L-3
附加几点解释:虽然说p1看来“相对”于p2并不前进,但是“绝对”来说,它还是前进的,那么迟早它会跑到圆圈上,而且不再出来
4000
。p2就更是了。所以,尽管有可能p1还没有进圆圈,p2已经跑完几圈了(想象一下圆圈很小,但是前面的直道部分很长的情况),但是p1迟早要进圈,演变成跑步问题。
========================================================
下面则再进一步:如何判断链表的环开始的位置呢?也就是环与链表的交点。
这个问题就更靠近脑筋急转弯的方向了。首先想到,如果还是p1和p2一起跑圈,那仍然会发生很多次相遇,但是这个相遇跟起点并无关系,想求出入口不可能。
那我们就分析一下,p1和p2相遇的时候到底发生了什么。在示意图中,假设p1和p2在P点第一次相遇。从环路入口到P点的距离为x,从P点到环路入口的另一段的距离为y。
那么显然,第一次相遇的时候,p1走过的总长度为x+z。那p2呢?我们首先假设p2比p1只多跑了一圈(方便理解,但并不影响最后结论,下面再证明所有的情况)。那么容易得到,p2走过的总长度为z+x+y+x。这个结论很显然也是表明p2比p1多跑了一圈(一圈的长度就是x+y,与前面的分析吻合)。由于p2的速度是p1的两倍,很容易得到一个结论:z+x+y+x
= 2 * (x+z)。也就是z = y。也就是说,相遇的点离环路入口的距离与链表直道的长度一样。
3,呵呵,得到这个结论似乎就离我们的答案很近了:如何才能找到这个入口位置呢?显然,让一个指针从相遇的P点出发,另外一个指针从链表头出发,以相同的速度前进,那么它们必然会在O点也就是环路入口相遇!
补充证明:设p2跑了n圈之后,才跟p1相遇(但请注意:p1一定是在自己的第一圈,因为不可能发生两个指针都在圈内,p2超过了p1但是没相遇的情况,前面的分析里说了),那么可以得到下面的等式:
z + n * (x+y) + x = 2 * (x+z)
最后可以得到下面的式子:z = n*(x+y) - x = (n-1)*(x+y) + y。 也就是说直道的长度等于n-1圈的长度加上y的长度,仍然不影响上面的结论:如果两个指针速度相同,一个指针从head出发,另一个从P点出发(跑n-1圈,再跑y),所花时间相等。它们一定会在O点相遇!
2,对于问题2,记录下问题1的碰撞点,slow和fast从该点开始,再次碰撞所走的长度 就是换的长度。
4,链表的长度可以由2,3得到的长度和求得。
5,
将其中的一个链表首尾相连,然后判断另一个链表是否带环即可。(问题就会演变成判断是否有环了
代码二
1、如何判断是否存在环?
2、如何知道环的长度?
3、如何找出环的连接点在哪里?
4、带环链表的长度是多少?
5、如何判断两个链表相交?
1,算法的思想是设定两个指针p,
q,其中p每次向前移动一步,q每次向前移动两步。那么如果单链表存在环,则p和q相遇;否则q将首先遇到null。
方法一:
(1)用两个指针p1和p2分别指向表头结点,即p1=p2=head
(2)p1和p2分别采用1和2作为步长遍历该链表。(注意,p2应该检查当前结点的下一个结点是否为NULL)
(3)如果p2遇到了NULL,则证明该链表没有环;若p1和p2在某时刻指向同一结点,则说明该链表有环
方法二:
(a)p从表头结点开始以1为步长遍历表,边遍历边将表反向
(b)如果p遇到NULL,则说明表没有环
(c)如果p最后等于head,则说明表有环,且记此时p所经过的表的结点数为l(l=2l1+c,l1和c的定义见方法一)
(d)p再从表头结点开始以1为步长遍历表,边遍历边反向,当遍历到l/2时,停止,设两个指针p1,p2均指向当前结点,然后分别从两个方向同时以1为步长遍历表(其中一个需要边遍历,边反向链表),当他们第相遇时,当前结点即为环头结点。且此时链表还原成原来的链表。
用两个指针来遍历这个单向链表,第一个指针p1,每次走一步;第二个指针p2,每次走两步;当p2 指针追上 p1的时候,就表明链表当中有环路了。
关于这个解法最形象的比喻就是在操场当中跑步,速度快的会把速度慢的扣圈.
可以证明,p2追赶上p1的时候,p1一定还没有走完一遍环路,p2也不会跨越p1多圈才追上.
我们可以从p2和p1的位置差距来证明,p2一定会赶上p1但是不会跳过p1的.
因为p2每次走2步,而p1走一步,所以他们之间的差距是一步一步的缩小,4,3,2,1,0 到0的时候就重合了.
根据这个方式,可以证明,p2每次走三步以上,并不总能加快检测的速度,反而有可能判别不出有环.
比如,在环的周长L是偶数的时候,初始p2和p1相差奇数的时候,p2每次走三步,就永远和p1不重合,因为他们之间的差距是: 5, 3 , 1,
L-1, L-3
附加几点解释:虽然说p1看来“相对”于p2并不前进,但是“绝对”来说,它还是前进的,那么迟早它会跑到圆圈上,而且不再出来
4000
。p2就更是了。所以,尽管有可能p1还没有进圆圈,p2已经跑完几圈了(想象一下圆圈很小,但是前面的直道部分很长的情况),但是p1迟早要进圈,演变成跑步问题。
========================================================
下面则再进一步:如何判断链表的环开始的位置呢?也就是环与链表的交点。
这个问题就更靠近脑筋急转弯的方向了。首先想到,如果还是p1和p2一起跑圈,那仍然会发生很多次相遇,但是这个相遇跟起点并无关系,想求出入口不可能。
那我们就分析一下,p1和p2相遇的时候到底发生了什么。在示意图中,假设p1和p2在P点第一次相遇。从环路入口到P点的距离为x,从P点到环路入口的另一段的距离为y。
那么显然,第一次相遇的时候,p1走过的总长度为x+z。那p2呢?我们首先假设p2比p1只多跑了一圈(方便理解,但并不影响最后结论,下面再证明所有的情况)。那么容易得到,p2走过的总长度为z+x+y+x。这个结论很显然也是表明p2比p1多跑了一圈(一圈的长度就是x+y,与前面的分析吻合)。由于p2的速度是p1的两倍,很容易得到一个结论:z+x+y+x
= 2 * (x+z)。也就是z = y。也就是说,相遇的点离环路入口的距离与链表直道的长度一样。
3,呵呵,得到这个结论似乎就离我们的答案很近了:如何才能找到这个入口位置呢?显然,让一个指针从相遇的P点出发,另外一个指针从链表头出发,以相同的速度前进,那么它们必然会在O点也就是环路入口相遇!
补充证明:设p2跑了n圈之后,才跟p1相遇(但请注意:p1一定是在自己的第一圈,因为不可能发生两个指针都在圈内,p2超过了p1但是没相遇的情况,前面的分析里说了),那么可以得到下面的等式:
z + n * (x+y) + x = 2 * (x+z)
最后可以得到下面的式子:z = n*(x+y) - x = (n-1)*(x+y) + y。 也就是说直道的长度等于n-1圈的长度加上y的长度,仍然不影响上面的结论:如果两个指针速度相同,一个指针从head出发,另一个从P点出发(跑n-1圈,再跑y),所花时间相等。它们一定会在O点相遇!
2,对于问题2,记录下问题1的碰撞点,slow和fast从该点开始,再次碰撞所走的长度 就是换的长度。
4,链表的长度可以由2,3得到的长度和求得。
5,
将其中的一个链表首尾相连,然后判断另一个链表是否带环即可。(问题就会演变成判断是否有环了
<pre name="code" class="cpp"><pre name="code" class="cpp">#include <stdio.h> typedef struct Node { int val; Node *next; }Node,*pNode; //判断是否有环 bool isLoop(pNode pHead) { pNode fast = pHead; pNode slow = pHead; //如果无环,则fast先走到终点 //当链表长度为奇数时,fast->Next为空 //当链表长度为偶数时,fast为空 while( fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; //如果有环,则fast会超过slow一圈 if(fast == slow) { break; } } if(fast == NULL || fast->next == NULL ) return false; else return true; } //计算环的长度 int loopLength(pNode pHead) { if(isLoop(pHead) == false) return 0; pNode fast = pHead; pNode slow = pHead; int length = 0; bool begin = false; bool agian = false; while( fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; //超两圈后停止计数,挑出循环 if(fast == slow && agian == true) break; //超一圈后开始计数 if(fast == slow && agian == false) { begin = true; agian = true; } //计数 if(begin == true) ++length; } return length; } //求出环的入口点 Node* findLoopEntrance(pNode pHead) { pNode fast = pHead; pNode slow = pHead; while( fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; //如果有环,则fast会超过slow一圈 if(fast == slow) { break; } } if(fast == NULL || fast->next == NULL) return NULL; slow = pHead; while(slow != fast) { slow = slow->next; fast = fast->next; } return slow; }
代码二
bool IsExitsLoop(slist * head) { slist * slow = head , * fast = head; while ( fast && fast -> next ) { slow = slow -> next; fast = fast -> next -> next; if ( slow == fast ) break ; } return ! (fast == NULL || fast -> next == NULL); } slist * FindLoopPort(slist * head) { slist * slow = head, * fast = head; while ( fast && fast -> next ) { slow = slow -> next; fast = fast -> next -> next; if ( slow == fast ) break ; } if (fast == NULL || fast -> next == NULL) return NULL; slow = head; while (slow != fast) { slow = slow -> next; fast = fast -> next; } return slow; }
相关文章推荐
- 判断一个链表中是否有环,并且得到环的入口位置
- 链表——判断链表是否有环以及环的入口结点
- 判断链表是否有环,环的入口以及环的长度
- 单链表中判断是否有环以及得出环的入口点(简单易懂)
- 判断链表是否带环,以及环的入口
- 判断单链表是否是循环链表以及找出循环链表入口
- 题目:①判断一个单向链表是否有环,如果有环则找到环的入口节点。 ②判断两个单向链表是否相交,如果相交则找到交点节点。
- 判断链表是否有环以及找出环的入口点知识总结
- 如何判断一个链表是否有环,如何确定入口
- 判断一个链表是否有环以及长度
- 判断链表是否有环以及查找环的入口点——淘宝笔试归来
- [算法]判断一个链表是否有环及环开始的位置
- 单向链表相交的第一个公共结点, 判断链表是否有环以及环的入口节点
- 如何判断一个链表是否有环,如果有环,并找出环的入口
- 判断一个链表是否有环,并找出环的入口
- 判断链表是否有环以及环的入口点,两链表是否有公共节点
- 判断链表是否有环以及查找环的入口点——淘宝笔试归来
- day03之判断链表带环以及求环的长度及环的入口点+一个类不能被继承及只能分别在栈堆上创建对象
- 链表面试题----判断一个单链表是否带环,若带环,求入口点和环的长度
- 判断链表是否带环,以及环的入口