顾名思义,快慢指针分为两个指针,一个是快的指针,一个是慢的指针。快慢指针主要用于判断链表中是否有环的存在。
现在我们设想一个场景:龟兔赛跑,龟和兔在同一起点同时出发,但是兔子的速度大于乌龟的速度。如果此时跑道是环形的,那么兔子一定会在某一时刻追上乌龟,换而言之,它们一定会再次相遇。但是如果是非环形跑道,那么兔子一定会先到终点然后停下来,而乌龟一定是在兔子后面抵达终点。
现在我们把这个场景抽离出来:乌龟就是慢指针,兔子就是快指针,跑道就是链表,起点就是表头节点head,终点就是NULL。
快慢二指针同时从表头head出发进行链表的遍历,如果快指针直接到达了终点NULL,说明此链表无环结构;如果快指针和慢指针相遇,说明快指针追上了慢指针,即此链表有环结构。
具体实现代码如下:
#include<stdbool.h>//因为我们定义的函数返回值是bool,即返回true或false,所以用到这个头文件
struct ListNode {
int val;
struct ListNode *next;
};//定义链表的单节点,分为数据域val和指针域next
bool hasCycle(struct ListNode *head) {
struct ListNode *slow=head;//定义慢指针并使其指向头节点
struct ListNode *fast=head;//定义快指针并使其指向头节点
while(fast&&fast->next){/*当(快指针指向的节点不为空 并且 快指针所指向的节点的下一个节点不为
空 时)因为若无环结构,fast一定会比slow先到终点,所以这里无需再判
断slow和slow->next是否为NULL。同时这里还包含了链表为空或者只有一
个头节点的情况,因为这两种情况说明链表肯定无环结构,所以直接返回
false*/
slow=slow->next;//慢指针往前走一步
fast=fast->next->next;//快指针往前走两步
if(slow==fast) return true;/*如果慢指针指向的节点等于快指针指向的节点,那么就说明二指针
相遇,即说明该链表有环结构*/
}
return false;
}
注:if(slow==fast)这里比较的一定是整个节点而非节点中的数据域,有些人可能会写成if(slow->val==fast->val),这是错误的,因为不同的节点的数据域是可以相同的,所以要根据此节点的数据域和指针域同时进行判断,即直接判断节点即可,不必区分指针域还是数据域。