您的位置:首页 > 其它

快慢指针判断单向链表是否有环及找环入口

2016-03-13 02:31 288 查看

前言

关于快慢指针找环入口的这个问题,之前巴特跟我聊到过,印象比较深,今晚看学长在做的面试题,里面就出现了这个小知识。

发现有些东西不经意间就会用到,于是便出现此文。以后要努力做到善于总结,乐于总结。

概念

快慢指针,所谓的快慢,就是指指针每次移动的步长,通常使快指针每次向前移动两步,慢指针每次向前移动一步。

判断链表环及找环入口

操作

从链表头节点开始,快慢指针同时开始移动,快指针每次移动2,慢指针每次移动1,若快指针最终与慢指针相遇,则表示链表有环,否则,则为无环。

有环情况下,快慢指针相遇时,慢指针位置不变,将快指针置回表头,步长改为每次移1,快慢指针同时开始移动,再次相遇处即为环的入口。

原理

判断是否有环就不解释了,下面主要解释,为什么可以那样找环入口。

[code]        ⬇️<-<-<-⬆️
♦️->->->⬇️->->->⬆️
A           B   C


只是个简单图,就不专门做图了,凑合表示下吧。

♦️也就是A的位置是头节点,B表示环入口处,C表示快慢指针第一次相遇处。

在C处相遇时,设慢指针跑了N步,也就是从A开始N步后会到达C。

快指针比慢指针走的快一倍,也就是走了2*N步。那么慢指针从C处再跑N步还会回到C处。

既然都会回到C处,那么必然会在B点第一次相遇。

所以我们在入口处再设一指针(用之前快指针即可),与慢指针用1步长同时前进,第一次相遇处就是环入口处。

代码

[code]/* 代码很简单 */
List* func(List* Head)
{
    List* fast, slow;
    fast = slow = Head;
    while(fast != slow && fast != NULL)
    {
        slow = slow->next;
        fast = fast->next;
        if(fast != NULL)
            fast = fast->next;
    }
    if(fast == NULL)
        return true;
    fast = Head;
    while(fast != slow)
    {
        fast = fast->next;
        slow = slow->next;
    }
    return fast;
}


其他应用

譬如,给定一有序链表,求其中位数,因为不知道链表的具体长度,常规做法是先遍历一次,确定链表的长度,再遍历到中点,求出中位数。

但其实还有个更巧妙的法子,很方便的求出中位数,就是用快慢指针。

仍然是快指针步长为2,慢指针步长为1,当快指针到达链表尾部的时候,快指针就处于中点位置.(会牵扯到链表总数奇偶的情况,判断下即可,这里就不多赘述了)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: