目录
做题链接:
1.什么是环形链表?
环形链表是一种特殊的链表数据结构,其链表最后一个结点的next指针指向链表中的某个结点,从而形成闭环。换句话说,链表里的最后一个结点的next指向链表中的某个结点,而不是通常情况下指向一个空指针(NULL)。如图所示:
由于环形链表不像普通链表一样最后一个结点的next指针指向空指针,所以我们不能像我们平时用pcur=pcur->next的方式去遍历链表,这样会造成死循环。
2.解题方法
我们需要采用快慢指针的方法来实现:
1.首先我们需要定义slow,fast指针指向头节点。
2.slow指针走一步,fast指针走两步,如果相遇(slow==fast)则返回这个位置,也就是证明此链表有环,就返回true。如果没有相遇,则继续循环这样走,直到跳出循环,返回false。
3.循环的结束条件为fast&&fast->next。
截图代码如下:
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
//快慢指针
ListNode* slow=head;
ListNode* fast=head;
//slow走一步 fast走两步
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
//相遇返回true
if(slow==fast)
{
return true;
}
}
//则链表不成环
return false;
}
3.分析
1.为什么跳出循环条件是fast&&fast->next,而不是fast->next&&fast?
1.当一个链表中有环时,fast和fast->next永远不会指向NULL
2.当一个链表中没有环时,fast一定会移动到链表的结尾;又因为fast一次移动两个节点,所以有两种情况:①fast移动两次后,刚好指向NULL,结束循环;②fast移动一次后就已经指向NULL,此时再进行移动,就会出现对NULL的解引用。
2.为什么slow要移动一步,fast要移动两步呢?
如图所示:slow一次走一步,fast一次走两步,fast比slow先进环。假设slow已经走到入环点,此时fast和slow之间的距离为N,接下来的追逐中,每追逐一次fast和slow之间的距离缩下一步。
也就是说:最开始的距离为N,第一次追逐后他们的距离为N-1,第二次追逐后距离为N-2,第三次为N-3,........,1,0,直到N为0为止,也就是说相遇了。
4.思考一下快指针一次走三步,四步,N步可以吗?
当fast一次走三步时:假设slow和fast的距离为N,随着追逐距离为:N-2-2-2-2....-2=0.
此时就会出现两种情况:
1.当N为偶数的时候:
N可以被减到0,快慢指针就会相遇,(在为减到0时,fast指针一直在slow指针的后面追逐slow指针)。
2.当N为奇数时:
此时随着追逐fast和slow并不会相遇N最后会等于-1,fast将slow套圈了。此时slow和fast之间的距离为C-1(C为环的长度)。就变成了slow追fast了。然后我们需要观察C-1的变化,(C-1)-2-2-2-2...-2,此时又会出现两种情况,当C-1的结果为2的倍数时,则此链表有环,如果C-1的结果不是2的倍数,则会死循环,此链表不是环形链表。