判断两个单向链表是否存在环
2014-03-30 15:33
197 查看
今天Mayuyu来带领你们讨论如下三个问题:
(1)如何判断一个单链表是否存在环 ?
(2)如果存在环,如何找到环的入口点?
(3)两个链表中有环时,如何判断相交?
问题一
我们设置两个指针,分别是fast和slow,初始都指向这个单向链表的表头,fast每次走两步,而slow每次走一步,
所以,我们知道如果有环,那么fast先进入环,slow后进入环,在经过若干次这样的步骤,必定会有fast与slow
相遇,那么我们就能判断是否存在环了。如果不存在环,则fast先走到链表尾。
所以我们很容易得到如下代码:
问题二
上面问题一我们已经能判断一个单向的链表是否存在环,如果一个单向链表存在环,我们如何求它的环入口点?
如下图
![](http://img.blog.csdn.net/20140330141958187)
首先,我们设head到入口点的距离为
![](http://img.blog.csdn.net/20140330142414640)
,入口点到相遇点的距离为
![](http://img.blog.csdn.net/20140330142743437)
,沿着相遇点继续走到入口点的距离为
![](http://img.blog.csdn.net/20140330142921890)
,
链表总长度为
![](http://img.blog.csdn.net/20140330143109031)
,fast指针与slow指针相遇时slow一共走了
![](http://img.blog.csdn.net/20140330143235343)
步,那么很明显fast就走了
![](http://img.blog.csdn.net/20140330143340718)
步,相遇时fast比
slow多走了
![](http://img.blog.csdn.net/20140330143513843)
圈。
所以我们很容易得到
![](http://img.blog.csdn.net/20140330143652687)
,即
![](http://img.blog.csdn.net/20140330143728734)
又由于
![](http://img.blog.csdn.net/20140330144013000)
,所以
![](http://img.blog.csdn.net/20140330144126625)
,得到:
![](http://img.blog.csdn.net/20140330144332218)
这个表达式说明从相遇点到入口点的距离与head到入口点的距离取余后是相等的。所以我们可以在相遇点和head处
各设置一个指针,然后同时走,它们会在入口处相遇,这样我们也就能找到这个入口了。
代码如下:
问题三
实际上,我们先要明确一个事实,那就是如果一个单链表有环,另一个单链表没有环,那么这两个单链表一定不会
相交。这是单链表的next指向的唯一性决定的,一个节点不可能有两个或者多个后继分支。
所以,如果是两个有环链表相交,那么它们一定存在一个公共的环,大致如下两个图形:
![](http://img.blog.csdn.net/20140330151700828)
![](http://img.blog.csdn.net/20140330151919359)
所以,明确了以上事实之后,我们可以这样来做:
先分别求出这两个有环链表的环的入口点,如果入口点相等,那么说明这两个有环链表就相交了。如果不相等,就有
两种情况:
(1)两个有环链表不相交
(2)它们相交但环入口点不同
那么我们如何判断,这个就比较简单了。
我们设一个环的入口点为port,在另一个环的入口点设置一个指针p往后走,如果一周内出现p->next == port,
那么说明这两个有环链表共环,也就是说相交,否则这两个有环链表不相交。
(1)如何判断一个单链表是否存在环 ?
(2)如果存在环,如何找到环的入口点?
(3)两个链表中有环时,如何判断相交?
问题一
我们设置两个指针,分别是fast和slow,初始都指向这个单向链表的表头,fast每次走两步,而slow每次走一步,
所以,我们知道如果有环,那么fast先进入环,slow后进入环,在经过若干次这样的步骤,必定会有fast与slow
相遇,那么我们就能判断是否存在环了。如果不存在环,则fast先走到链表尾。
所以我们很容易得到如下代码:
bool isLoop(list *head) { list *slow = head; list *fast = head; while(fast && fast->next) { slow = slow->next; fast = fast->next->next; if(slow == fast) return true; } return false; }
问题二
上面问题一我们已经能判断一个单向的链表是否存在环,如果一个单向链表存在环,我们如何求它的环入口点?
如下图
首先,我们设head到入口点的距离为
,入口点到相遇点的距离为
,沿着相遇点继续走到入口点的距离为
,
链表总长度为
,fast指针与slow指针相遇时slow一共走了
步,那么很明显fast就走了
步,相遇时fast比
slow多走了
圈。
所以我们很容易得到
,即
又由于
,所以
,得到:
这个表达式说明从相遇点到入口点的距离与head到入口点的距离取余后是相等的。所以我们可以在相遇点和head处
各设置一个指针,然后同时走,它们会在入口处相遇,这样我们也就能找到这个入口了。
代码如下:
list *FindPort(list *head) { list *slow = head; list *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; }
问题三
实际上,我们先要明确一个事实,那就是如果一个单链表有环,另一个单链表没有环,那么这两个单链表一定不会
相交。这是单链表的next指向的唯一性决定的,一个节点不可能有两个或者多个后继分支。
所以,如果是两个有环链表相交,那么它们一定存在一个公共的环,大致如下两个图形:
所以,明确了以上事实之后,我们可以这样来做:
先分别求出这两个有环链表的环的入口点,如果入口点相等,那么说明这两个有环链表就相交了。如果不相等,就有
两种情况:
(1)两个有环链表不相交
(2)它们相交但环入口点不同
那么我们如何判断,这个就比较简单了。
我们设一个环的入口点为port,在另一个环的入口点设置一个指针p往后走,如果一周内出现p->next == port,
那么说明这两个有环链表共环,也就是说相交,否则这两个有环链表不相交。
相关文章推荐
- 如何判断两个有环单向链表是否有重合结点
- [算法练习FindLoop]判断单向链表是否存在循环/循环入口/环长度
- 判断两个单向链表是否有相交,并找出交点。
- 判断一个单向链表中是否存在环
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断单链表是否存在环,判断两个链表是否相交
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断单链表是否存在环,判断两个链表是否相交
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 如何判断两个单向链表是否有相交,并找出交点
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断单链表是否存在环,判断两个链表是否相交问题详解(转)
- 判断一个单向链表中是否存在环
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断两个单向链表是否相交
- 判断单链表是否存在环以及两个链表是否相交
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断单链表是否存在环,判断两个链表是否相交问题详解