链表有环相及其关问题解法
经典老番 题目:链表上的环如何判断,找出环入口,环长度,环上节点。。。。
结构定义与环的创建
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;
环上节点
有了长度,有了起点,直接遍历就行了