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

一、判断单链表是否存在环

这个问题有很多方法,最容易想到的就是记录每个节点记录的次数。这里也介绍的是另一种简单而常见的方法

快慢指针法:

定义两个指针slow, fast。slow指针一次走1个结点,fast指针一次走2个结点。如果链表中有环,那么慢指针一定会再某一个时刻追上快指针(slow == fast)。如果没有环,则快指针会第一个走到NULL

 1 int has_cycle(node *head) {
 2     if (head == NULL)  return false;
 3     node* fast = head;
 4     node* slow = head;
 5 
 6     while (1)
 7     {
 8         if (slow->next != NULL)  slow = slow->next;        //慢指针走一步
 9         else   return false;
10         if (fast->next != NULL && fast->next->next != NULL)  fast = fast->next->next;  //快指针走两步
11         else  return false;
12 
13         if (slow == fast)  return true;
14     }
15 }

二、寻找环的入口点

其中一个回到起点:

当fast按照每次2步,slow每次一步的方式走,发现fast和slow重合,确定了单向链表有环路。接下来,让fast回到链表的头部,重新走,每次步长1,那么当fast和slow再次相遇的时候,就是环路的入口了。

证明:

       在fast和slow第一次相遇的时候,假定slow走了n步,环路的入口是在p步,那么

  slow走的路径: p+c = n;(1) c为fast和slow相交点 距离环路入口的距离

  fast走的路径: p+c+k*L = 2*n;(2), L为环路的周长,k是整数

  fast从头开始走,步长为1.

  经过n步,fast和slow都会到达p + c这一点。将(2)-(1)得k*L = n,说明n是L的倍数,同时p + c = n,

  所以fast和slow都走p步时,fast距(p + c)差c,slow还差c回到(p + c),所以p是他们的第一个交点,之后的轨迹就一模一样了。

 1 node* find_loopport(node * head)
 2 {
 3     node* fast = head;
 4     node* slow = head;
 5 
 6     //两个互指不考虑
 7     //判断是否存在环,如果存在得到相遇位置
 8     while (fast && fast->next)
 9     {
10         slow = slow->next;
11         fast = fast->next->next;
12         if (fast == slow)  break;
13     }
14     //fast到达NULL,表示不存在环
15     if (fast == NULL || fast->next == NULL)  return NULL;
16 
17     //将一个指针移到开始处,步长都变成一
18     fast = head;
19     while (slow != fast)
20     {
21         slow = slow->next;
22         fast = fast->next;
23     }
24     return  slow;
25 }

猜你喜欢

转载自www.cnblogs.com/lfri/p/9611090.html