链表之快慢指针续

来源:互联网 发布:宿舍破解版路由器mac 编辑:程序博客网 时间:2024/05/31 00:40

之前解决了如何判断一个单链表是否存在环的问题。

那:如果要求出环的长度呢?

       如果要求出环的入口点呢?

一、求出带环单链表环的长度

求长度,就是希望有个指针能够遍历环中的每一个元素,然后记下经过的节点数就好了。

当fast==slow的时候,fast和slow已经在环中了

第一种方法:用p记录下fast所指的节点,q从这个节点开始遍历,当q再次等于p的时候,说明已经在环里走了一圈了,经过的节点数就是环的长度。

int loopLength1(Node *head){    Node *slow, *fast;    slow = fast = head;    while(fast && fast -> next)    {        fast = fast -> next -> next;        slow = slow -> next;        if(fast == slow)            break;    }    if(fast == slow)    {        Node *p = fast;        Node *q = fast -> next;        int length = 1;        while(p != q)        {            q = q -> next;            ++length;        }        return length;    }    return -1;}

第二种方法:fast 与 slow 第一次相遇开始计数,当它们第二次相遇时,我们可以证明,它们整整走了一圈,仍然指向第一次相遇时指向的节点。为了标记是否计数以及是否是第二次相遇,就需要用到两个bool类型的变量作为标记,分别是start 和 again

证明:     若环的长度为n, 第二次相遇时slow走了x步

               那么一方面fast走了2x步,另一方面fast走了x+n步。所以x等于n 即它们刚好走了一圈,回到了原点

int loopLength2(Node *head){    Node *slow, *fast;    slow = fast = head;    bool start = false,again = false;    int length = 0;    while(fast && fast -> next)    {        fast = fast -> next -> next;        slow = slow -> next;        //如果再一次追赶上        if(fast == slow && again)            break;        //如果第一次追赶上,则进行第二次追赶        else if(fast == slow && !again)        {            start = true;            again = true;        }        if (start) ++length;    }    if(fast == slow && again)        return length;    else return -1;}

二、求出环的入口点


这里有个论断,当fast slow第一次相遇时,slow一定还没有遍历完整个链表。自己画了几次发现是这样,具体证明没找到。设a是从head到入口点的长度,x是入口点到相遇点的长度,l是链表总长度

假设slow指针走了s步,则2s = s + nr, 得出s = nr ,又s = a + x

所以a + x = nr = (n-1)r + r = (n - 1)r + l - a

即 a + x = l - a - x

           a= (n - 1)r + l - a - x

l - a - x指的是从相遇点到入口点的长度

a指的是从head到入口点的长度

这个式子表明:从head出发的指针与从fast 和 slow相遇点出发的指针一定会在某个点相遇,它们相遇之处就是环的入口处。

好吧,算法:当fast和slow相遇后,令slow = head,fast不变,两者继续向后移动,知道两指针相遇,相遇之处就是环的入口处。

Node *findLoopPort(Node *head){    Node *slow, *fast;    slow = fast = head;    while(fast && fast -> next)    {        fast = fast -> next -> next;        slow = slow -> next;        if(fast == slow)            break;    }    if(fast == slow)    {        slow = head;        while(fast != slow)        {            fast = fast -> next;            slow = slow -> next;        }        return slow;    }    return NULL;}


 




0 0