带环单链表的环入口点

判断一个单链表是否带环,我们可以设置两个指针,一快一慢,慢的指针每次走一步,快的指针每次走两步,如果在遍历过程中,快慢指针相遇,则表明链表有环,否则无环;而,如何找到环的入口点呢?

给出一个定理:快慢指针的相遇点到环入口点的距离等于头结点到环入口点的距离;

LinkList Node {
    int value;
    LinkList next;
};

LinkList findCircleNode(LinkList *head) {
    LinkList *slow = head;
    LinkList *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;
    }
    return slow;
}

假设链表在(甩尾)环外长度为 a(结点个数),环内长度为 b 。
则总长度(也是总结点数)为 a+b 。
从头开始,0 base 编号。
将第 i 步访问的结点用 S(i) 表示。i = 0, 1 …
当 i<a 时,S(i)=i ;
当 i≥a 时,S(i)=a+(i-a)%b 。
分析追赶过程:
两个指针分别前进,假定经过 x 步后,相遇。则有:S(x)=S(2x)
由环的周期性有:2x=tb+x 。得到 x=tb 。
另外,相遇时,必须在环内,不可能在甩尾段,有 x>=a 。
连接点为从起点走 a 步,即 S(a)。
S(a) = S(tb+a) = S(x+a)。
得到结论:从碰撞点 x 前进 a 步即为连接点。
根据假设易知 S(a-1) 在甩尾段,S(a) 在环上,而 S(x+a) 必然在环上。所以可以发生碰撞。
而,同为前进 a 步,同为连接点,所以必然发生碰撞。
综上,从 x 点和从起点同步前进,第一个碰撞点就是连接点。
/
假设单链表的总长度为L,头结点到环入口的距离为a,环入口到快慢指针相遇的结点距离为x,环的长度为r,慢指针总共走了s步,则快指针走了2s步。另外,快指针要追上慢指针的话快指针至少要在环里面转了一圈多(假设转了n圈加x的距离),得到以下关系:
s = a + x;
2s = a + nr + x;
=>a + x = nr;
=>a = nr - x;
由上式可知:若在头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口节点;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值