判断单链表中是否有环,如果有环则找到环的入口地址

来源:互联网 发布:新浪模拟炒股软件 编辑:程序博客网 时间:2024/06/15 03:29

  由编程之美P261页下面程序改错涉及开来。


判断有没有环比较容易,设两个指针指向头节点,一个快点走,一个慢点走,如果有环,两者必会相遇。这里我们设一个一次走两步,一个一次走一步


   关键是要找到环的入口地址:

下面证明如何得到入口地址


假设环长为L,起始点到环入口长度为a,环长度为r,设慢指针和快指针相遇前,慢指针在环内走了x步(快指针已经走了n圈),同时假设慢指针已经走了s步,则快指针走了2s步。
则有:2S = S + n r   ;则s = nr;

又 a + X  = S;故a+X = nr = (n-1)r+r = (n-1)r + L-a;则a = (n-1)r + L-a-X;含义为环入口距离起点的距离和相遇点距离环入口点的距离相等。


这里a = (n-1)r + L-a-X

可能比较难理解,可以这样想,假设两个指针,一个从头节点开始走,一个从相遇点开始走,两个都一步步走


当走了a(长度)之后,头节点开始走的现在刚好走到了环的入口地址(这个可以理解吧)

从相遇点走的也走了a步我们由上面知道a = (n-1)r + L-a-X       (n-1)r 为环得到长度倍数,可以看成先走的,那么此时走了(n-1)r又回到了相遇点,接着走剩下的 L-a-x,L-a为环长,L-a-x为环中剩下的距离,所有相遇点走的也刚好走到了环口。

 

故让慢指针回到起点,快指针从相遇点开始继续走,当两者相等时,则为环入口地址。

代码如下:


node* first_loop_port(node *head){    node *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;}


 

0 0