有环的定义是,链表的尾节点指向了链接中间的某个节点。比如下图,如果单链表有环,则在遍历时,在通过6之后,会重新回到3,那么我们可以在遍历时使用两个指针,看两个指针是否相等。
此题面试经常见,算法思想是用两个指针p,q,p每次走两步,q每一走一步。如何单链表有环,则p和q相遇;否则p先到达NULL。
有人要问了,为什么单链表有环时p和q就会相遇呢?
假设单链表的长度是n,且带环,那么当走到第i步时,q指向i mod n,p指向2*i mod n.即当 i mod n == 2*i mod n时,p与q相遇。
即(2*i-i) mod n == 0,即i mod n ==0.即i == n.此时p和q第一次相遇.
可以简单理解为p和q同时在操场跑步,其中p的速度是q的两倍,当他们两个同时出发时,q跑一圈到达起点,而p此时也刚好跑完两圈到达起点。
上代码:
int huan()
{
link p = q = head;
while(p != NULL && p->next != NULL)
{
p = p->next->next; //p每次走两步
q= q->next; //q每次走一步
if(p == q)
return 1;
}
return 0;
}
条件判断只是为了当链表没环时跳出循环
网上很多解法还判断了q != NULL,其实没必要判断,因为p走的比q快,当q == NULL 时,p其实早就等于NULL了。
条件判断为何还要判断p->next呢?
因为当单链表没环时,每次p的速度是q的2倍,如果p->next == NULL,这时如果继续走,就会出现
p = NULL->next;这是断错误。