快慢指针能判断链表有环是因为速度差为整数的两指针在环中必相遇;若无环,fast先达nullptr;定位入口需将slow重置至head后与fast同速前进,再次相遇即入口。
为什么快慢指针能判断链表有环
因为环的存在会让两个以不同速度前进的指针最终相遇——就像操场跑圈,快的人迟早追上慢的人。前提是两者都在环里持续移动,且速度差为整数(通常设为 2:1)。若无环,
会先走到
;若有环,它们必在某次迭代中指向同一节点。
和
的初始位置与移动逻辑
必须都从头节点开始(不能一个在头、一个在
),否则可能跳过长度为 1 的环(自环)。移动时严格遵守:
,
,且每次移动前都要检查
和
是否为空:
漏判
会导致解引用空指针,崩溃
把
拆成两步并中间不检查,同样危险
如果允许环入口在头节点(如单节点自环),起始位置不对会直接错过
如何用 Floyd 法定位环的入口节点
相遇只说明有环,但入口在哪?此时将
重置回
,
保持在相遇点,然后两者都每次走 1 步:
,
。再次相遇的位置就是环入口。
原理是数学推导:设头到入口距离为
,入口到相遇点距离为
,环剩余部分为
,则
→
→
。所以从头和相遇点同速出发,必然在入口撞上。
C知道
CSDN推出的一款AI技术问答工具
下载
立即学习
“
C++免费学习笔记(深入)
”;
必须重置
到
,不能复用原指针位置
循环条件是
,不是
,因为二者都在环内稳定移动
该步骤仅在确认有环后执行,否则
可能为
,解引用出错
边界情况和实际调试建议
写完别急着交,手动模拟几个关键 case:
输入:直接返回
,避免空指针解引用
单节点无环:
,
检查失败,循环不进,返回
单节点自环:
,第一次移动后
,立刻返回
环在末尾(如 A→B→C→D→C):需要多轮才能相遇,但一定发生
最容易被忽略的是:Floyd 法无法直接给出环长,也不能区分“伪环”(比如野指针指向了堆上某个随机地址)——它只对合法的、由
构成的单向闭环有效。真实项目中,如果链表节点生命周期混乱,检测结果可能误导。
fastnullptrslowfasthead->nextslow = slow->nextfast = fast->next->nextfastfast->nextwhile (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return true;
}fast->next == nullptrfast = fast->next->nextslowheadfastslow = slow->nextfast = fast->nextabc2(a + b) = a + b + n(b + c)a = n(b + c) - ba ≡ c (mod 环长)slowheadslow != fast!= nullptrfastnullptrnullptrfalsehead->next == nullptrfast->nextfalsehead->next == headslow == fast == headtruenext