链表有环相及其关问题解法

链表有环相及其关问题解法

经典老番 题目:链表上的环如何判断,找出环入口,环长度,环上节点。。。。

结构定义与环的创建

typedef struct node
{
	int data;
	node* next;
	node(int dt):data(dt), next(NULL){}
}node;
node n1 = node(1);
node n2 = node(2);
node n3 = node(3);
node n4 = node(4);
node n5 = node(5);
node n6 = node(6);
node n7 = node(7);
node n8 = node(8);

n1.next = &n2;
n2.next = &n3;
n3.next = &n4;
n4.next = &n5;
n5.next = &n6;
n6.next = &n7;
n7.next = &n8;
n8.next = &n3;

最后拿到的头节点是n1
在这里插入图片描述

判断环

使用快慢指针去判断一个链表是否有环,就像跑操场,同时起跑,跑的快的人一直跑,总有一刻会领先慢的人一整圈,二人幸终 相遇

  • 慢指针一次一步,快指针一次两步
  • 值得注意的是快指针走之前,看一下前面是否为空
  • 只要相遇,说明发现环了,break
bool flag = false;
node* fast = &n1;
node* slow = &n1;
while(slow && fast && fast->next)
{
	fast = fast->next->next;
	slow = slow->next;
	
	if(fast == slow)
	{
		flag = true;
		break;
	}
}

找环入口

稍加思索可以发现:

从相遇点正向遍历到环入口的距离 = 从起点正向遍历到环入口的距离

慢指针走不完一圈,那么相遇点到起点的距离是慢指针走的距离,这时候只需要再走【表长 - 相遇节点顺序编号 + 1】步,即可到达环入口,如果从环入口,倒着走【表长 - 相遇节点顺序编号 + 1】,即可到达表头

可是很多时候我们不知道节点编号,所以使用两个指针p1,p2,一个从头开始,一个从相遇节点开始,直到碰头,碰头节点就是环入口
在这里插入图片描述

bool flag = false;
node* fast = &n1;
node* slow = &n1;
node* p1 = &n1;
node* p2 = &n1;
// 找相遇节点 
while(slow && fast && fast->next)
{
	fast = fast->next->next;
	slow = slow->next;
	
	if(fast == slow)
	{
		flag = true;
		p1 = fast;
		break;
	}
}
// p2从头,p1从相遇点开始,走到碰头就是环入口 
while(p1 != p2)
{
	p1 = p1->next;
	p2 = p2->next;
}
cout<<"环入口:"<<p1->data<<endl;

环长度

这个比较简单,再走一遍就好。。。。
在这里插入图片描述

bool flag = false;
node* fast = &n1;
node* slow = &n1;
// 找相遇节点 
while(slow && fast && fast->next)
{
	fast = fast->next->next;
	slow = slow->next;
	
	if(fast == slow)
	{
		flag = true;
		break;
	}
}
// 再走一遍环 
int len = 0;
do
{
	len += 1;
	fast = fast->next->next;
	slow = slow->next;
}while(slow != fast);

cout<<"环长度:"<<len<<endl; 

环上节点

有了长度,有了起点,直接遍历就行了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值