快慢指针检测链表是否有环的标准解法是:两指针从头出发,slow每次走1步、fast每次走2步;若相遇则有环,若fast或fast->next为空则无环。需先判空再移动,且初始须检查head和head->next是否为空。

怎么用快慢指针检测链表是否有环
能,而且是标准解法。核心就一句话:两个指针从头出发,一个每次走1步(slow),一个每次走2步(fast),如果相遇,说明有环;如果fast走到nullptr,说明无环。
关键不是“怎么走”,而是“边界怎么判”。很多人写错,是因为没想清楚fast的下一步是否合法。
-
fast非空才能读fast->next,所以循环条件必须先检查fast != nullptr && fast->next != nullptr - 不能只写
fast != nullptr——因为fast->next可能为nullptr,再取fast->next->next就崩了 - 更新顺序必须是先判、再走:先确认
fast和fast->next都非空,才让fast = fast->next->next
示例片段:
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return true;
}
return false;
为什么快慢指针一定能在环内相遇
不是靠运气。只要存在环,且fast比slow快1步/轮,相对速度就是1,相当于slow静止、fast以1步/轮逼近——环再大也终会追上。
立即学习“C++免费学习笔记(深入)”;
但这个结论成立有两个隐含前提:
-
fast必须严格比slow快(比如走3步也行,但走2步最稳,避免跳过slow) - 环入口位置不影响相遇性,但会影响第一次相遇点离环入口的距离——这点在找环起点时才重要
- 如果
fast走得太快(比如每次走10步),在小环里可能反复绕圈却错过slow,反而失效
遇到空链表或单节点怎么处理
直接返回false。这是最容易漏掉的边界。
- 头指针为
nullptr→ 无节点,不可能有环 - 只有一个节点(
head->next == nullptr)→ 无法自指(C++中不认为单节点自环是合法链表结构),也返回false - 这些情况必须在进入
while前判断,否则fast->next访问会崩溃
建议开头加两行:
if (head == nullptr || head->next == nullptr) return false;
实际调试时常见报错和定位方法
最常见的不是逻辑错,而是运行时报EXC_BAD_ACCESS或segmentation fault,本质都是野指针解引用。
- 错误现象:
fast = fast->next->next崩溃 → 没检查fast->next是否为空 - 错误现象:循环不退出 →
fast进了环但slow没跟上 → 很可能是slow或fast初始化错了(比如fast = head->next->next但没保证head->next存在) - 验证技巧:在循环里加
cout ,看地址是否重复出现(注意别在OJ环境用,会TLE)
真正难的不是写对算法,而是把每一步指针访问的合法性想全。哪怕多一行空指针判断,也比core dump后翻半天强。










