手写单向链表反转应避免边遍历边改next的直觉陷阱,须用prev、curr、next_temp三变量严格控制引用交接,初始化prev=none、curr=head,循环中先缓存curr.next再改curr.next=prev,最后更新prev和curr,返回prev;空链表与单节点需单独处理,反转后需用节点id验证无环无断链。

为什么手写单向链表时反转别直接改指针顺序
手写单向链表的 reverse() 容易陷入“边遍历边改 next”的直觉陷阱,结果在多处漏判空节点或提前断链,导致 AttributeError: 'NoneType' object has no attribute 'next'。真正安全的做法是明确区分「遍历位置」和「重建位置」,用三个变量(prev、curr、next_temp)严格控制每步的引用交接。
- 必须先缓存
curr.next再改curr.next = prev,否则后续节点丢失 - 头节点反转后变成尾节点,其
next必须显式设为None,不能依赖初始值 - 空链表(
head is None)和单节点链表(head.next is None)要单独处理,否则循环逻辑越界
如何用迭代法在O(1)额外空间内完成反转
递归反转看似简洁,但会消耗 O(n) 栈空间,且容易触发 RecursionError(Python 默认递归深度约 1000)。迭代法只用固定三个变量,空间稳定 O(1),也更容易调试指针状态。
- 初始化:
prev = None,curr = head - 循环条件:只要
curr is not None就继续 - 每轮操作顺序不能乱:
next_temp = curr.next→curr.next = prev→prev, curr = curr, next_temp - 循环结束时
prev指向原链表尾、现链表头,返回prev
def reverse_iterative(head):
prev, curr = None, head
while curr:
next_temp = curr.next
curr.next = prev
prev, curr = curr, next_temp
return prev
反转后如何验证链表结构没被破坏
反转操作后常出现「部分节点丢失」或「成环」,尤其当原链表有重复值或手动调试时误连节点。不能只靠打印值,必须检查指针拓扑。
- 用集合记录已访问节点 ID:
seen = set(),遍历时把id(node)加入,重复则成环 - 从新头节点出发计数,与原长度对比;若中途遇到
None提前终止,说明断链 - 避免用
node.val去查重——值可重复,ID 才唯一标识节点实体
简单验证函数示例:
def is_valid_linked_list(head):
seen = set()
curr = head
while curr:
if id(curr) in seen:
return False # cycle detected
seen.add(id(curr))
curr = curr.next
return True
什么时候该用双指针迭代而不是切片模拟
有人用 list 存所有节点再切片反转(nodes[::-1]),虽快但违背链表本质:它把链表当数组用了,丢失了「动态增删 O(1)」的优势,且额外占用 O(n) 空间。真需要频繁反转,说明设计可能有问题——链表本身不擅长随机访问或批量倒序。
- 仅当链表极短(
- 若业务中反转后立刻遍历输出,用迭代反转 + 一次遍历更省空间
- 注意 Python 的
is和==区别:比较节点是否同一对象用is,别用==触发意外的__eq__逻辑
链表反转的坑不在算法思想,而在每一步指针交接的原子性——少一次缓存、多一次赋值,整条链就散了。动手前先默念三遍:next_temp = curr.next、curr.next = prev、prev, curr = curr, next_temp。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











