链表环问题

链表环问题:

给定一个链表,判断该链表中是否有环?如果有的话,环的长度是多少?环的入口是哪个节点?

解决:

使用快慢指针策略,两个指针都从头指针出发,快指针每次走两步,慢指针每次走一步。

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;
 } 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值