链表环问题:
给定一个链表,判断该链表中是否有环?如果有的话,环的长度是多少?环的入口是哪个节点?
解决:
使用快慢指针策略,两个指针都从头指针出发,快指针每次走两步,慢指针每次走一步。
1.判断链表是否有环?
如果快慢节点相遇,那么链表有环。
2.如果有环,环的长度是多少?
快慢指针相遇后,固定其中一个指针(如快指针)不动,另一个指针(即慢指针)以步长为1前进,下次相遇之前,慢指针走的步数就是环的长度
3.如果有环,环的入口是哪个节点?
有环时,第一次相遇后,慢指针回到起点,快指针位置不变,此时两者都一步一步向前走,再次相遇则是环的入口。解释:
假设起点到环入口距离为m,环长度为n,则第一次相遇时,快指针走的步数为2s=m+A*n+k(不一定就在环入口相遇,所以加上k),慢指针走的步数为: s=m+B*n+k(在圈很大的时候,也有可能慢指针绕了好几圈才和快指针相遇),所以两者走的步数差为: 2s-s=s=(A-B)*n,即s是环长度的整倍数,这时候慢指针回到头指针,快指针仍然在原地,两者同样的速度(每次一步)向前走,当慢指针走了m步走到环入口时,快指针从最一开始走了m+2s步,因为s是环长度的整倍数,那么久可以判定此时快指针也在环入口了,即此时快指针和慢指针在环入口相遇了 。
#include<iostream>
using namespace std;
struct Node{
Node(int value)
{
this->value=value;
}
Node * next;
int value;
};
bool check_circle(Node *head)
{
Node *fast=head;
Node *slow=head;
while(fast && fast->next) //因为fast走得比slow快,所以只需要判断fast和fast-next是不是空就行
{ //而不能使用while(slow->next && fast->next->next)判断,因为连用fast->next->next就跨步了
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
return true;
}
return false;
}
int get_loop_length(Node * head )
{
if (!check_circle(head))
return 0;
int loop_length=0;
Node *fast=head;
Node *slow=head;
bool is_first_meeted=false;
bool is_second_meeted=false;
while(fast && fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
if(is_first_meeted) //有环时,当第一次相遇后,开始计数,一直到再次相遇,快指针比慢指针夺走了一圈,走得步数s就是环的长度
break; //因为走得步数s就是慢指针走得步数s,而快指针走了2s, 相差的步数s正好是快指针比慢指针多走的步数,就是环的一圈
else
is_first_meeted=true;
if (is_first_meeted)
loop_length++;
}
return loop_length;
}
Node * get_entrance(Node *head)
{
Node *fast=head;
Node *slow=head;
bool is_find_circle=false;
while(fast && fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
{
is_find_circle=true;
break;
}
}
if(!is_find_circle) return NULL;
slow=head;
while(slow!=fast)
{
slow=slow->next;
fast=fast->next;
}
return slow;
}
Node * init()
{
Node *n1=new Node(1); Node *n2=new Node(2);
Node *n3=new Node(3); Node *n4=new Node(4);
Node *n5=new Node(5);
Node *head=n1;
n1->next=n2;n2->next=n3;n3->next=n4;
n4->next=n5;n5->next=n2;
return head;
}
int main()
{
Node * head=init();
bool have_loop=check_circle(head);
int loop_length=get_loop_length(head);
Node *entrance=get_entrance(head);
cout<<"have_loop:"<<have_loop<<" looop_length:"<<loop_length<<" entrance:"<<entrance->value<<endl;
return 0;
}