弗洛伊德判圈算法核心是用slow(步长1)和fast(步长2)双指针遍历单链表,若相遇则有环,若fast遇nullptr则无环;C++实现需先判空和单节点,循环条件为fast&&fast->next,移动后立即比较指针是否相等。

弗洛伊德判圈算法的核心逻辑是什么
它不依赖额外空间,只用两个指针——slow 和 fast,在单链表上同步移动:slow 每次走 1 步,fast 每次走 2 步。如果链表有环,二者必在环内相遇;若 fast 先走到 nullptr,说明无环。
如何用 C++ 实现基础判环(无环返回 false,有环返回 true)
注意边界:空链表或仅一个节点时,fast->next 可能非法,必须先检查 fast 和 fast->next 是否为 nullptr。
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
bool hasCycle(ListNode *head) {
if (!head || !head->next) return false;
ListNode *slow = head;
ListNode *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return true;
}
return false;
}
为什么 fast 要走两步而不是三步或更多
走两步是效率与正确性平衡的结果:
- 若
fast走 3 步,可能跳过slow,导致一次循环内不相遇,需更多轮才能捕获,但不破坏正确性 - 但走 2 步能保证:只要存在环,相对速度为 1,
fast必然在有限步内追上slow(数学上可证最多绕环一圈就相遇) - 走 >2 步会增加空指针解引用风险(如
fast->next->next->next),且无性能收益
常见误写和崩溃点
最常出错的是循环条件和移动顺序:
立即学习“C++免费学习笔记(深入)”;
- 错误写法:
while (fast->next && fast)—— 顺序反了,fast为nullptr时访问fast->next直接段错误 - 错误写法:先移动再判断(如把
if (slow == fast)放在移动之后但没处理初始重合)—— 若链表只有一个节点且自环(head->next == head),初始slow == fast,但未进循环就被跳过 - 正确做法:循环条件严格为
fast && fast->next,且每次移动后立即判断相等
环检测本身不难,但指针操作的边界稍一松懈就会 crash,尤其是和 LeetCode 测试用例里各种极端结构(空、单节点、自环、长链+小环)打交道时,条件顺序和判空缺一不可。











