问题:给定一个有环链表,实现一个算法返回环路的开头结点
一、检查一个链表是否存在环路
检查链表是否存在环路,常用的比价简单的做法较FastRunner/SlowerRunner法。FastRunner一次移动两步,SlowerRunner一次移动一步,这就好比两辆赛车绕着同一环形跑道以不同的速度前进,最终必然会碰到一起。
question:有可能存在不发生碰撞吗?绝对不可能,假定FastRunner超过了SlowerRunner,情况(1)SlowerRunner处于位置i,FastRunner处于位置i+1,那么往前一步SlowerRunner就i-1,FastRunner处于位置((i+1)-2)=i-1位置,两者碰在了一起。
情况(2)SlowerRunner处于位置i,FastRunner处于位置i+2,那么往前两步,SlowerRunner处于i-2,FastRunner处于(i+2-2*2)=i-2,两者碰在了一起。
二、实现返回环路开头结点。
思路:1.通过链表指针实现,FastPointer的移动速度是SlowerPointer的两倍。当SlowerPointer走了k个结点进入环路时,FastPointer已经进入链表环路k个结点。也就是说FastPointer和SlowerPointer相距LOOP_SIZE-k个结点。
2.若SlowerPointer每走一个结点,FastPointer就走两个结点,每走一次,两者的距离就会更近一个结点,因此,在走了LOOP_SIZE-k次后,它们会碰在一起,这时两者距离环路开始处有k个结点。
3.链表首部和环路处也相距k个结点。因此,若其中一个指针保持不变,另一个指针指向链表首部,则两个指针会在环路起始位置处相遇。
算法代码如下:
struct Node
{
Type data;
Node* next;
}
Node* FindBeginnig(Node* head)
{
Node* fast=head;
Node* slower=head;
//找到碰撞位置,将位于量表中LOOP_SIZE步位置
while(fast!=NULL || fast->next != NULL)
{
fast=fast->next->next;
slower=slower->next;
if(fast==slower)
{
break;
}
}
//错误检查,没有碰撞出,也即没有环路
if(fast==NULL || fast->next==NULL)
return NULL;
slower=head;
while(slower!=fast)
{
slower=slower->next;
fast=fast->next;
}
//此时两指针均指向环路开始处
return fast;
}
版权声明:本文为u012260238原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。