用三个指针因单向链表无前驱,需保存prev、curr、next;顺序为缓存next→改curr→更新prev→更新curr;返回prev而非curr。

迭代反转链表:为什么用三个指针而不是两个
因为单向链表没有前驱指针,必须显式保存 prev、curr 和 next 三者状态,否则一移动 curr 就丢掉后续节点。常见错误是先改 curr->next 再取 next,导致空指针解引用或循环链表。
实操建议:
- 初始化
prev = nullptr,curr = head,进循环前先缓存next = curr->next - 顺序固定:改指针 → 更新 prev → 更新 curr(不能颠倒)
- 返回值是
prev,不是curr(循环结束时curr已为nullptr)
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}递归反转链表:函数返回值到底是谁
递归版本的返回值始终是原链表尾节点(即新链表头),不是当前层的 head。很多人误以为要返回 reverseList(head->next) 的结果再处理,其实关键在「递归调用后」才改指针——此时 head->next 已指向新链表尾,只需让它的 next 指回 head,再断开 head->next 即可。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
- 忘记置空
head->next = nullptr,导致环(尤其测试用例含单节点时必出错) - 在递归调用前就修改
head->next,破坏递归前提 - 边界判断写成
if (!head->next),漏掉head == nullptr情况
ListNode* reverseList(ListNode* head) {
if (!head || !head->next) return head;
ListNode* newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
}迭代 vs 递归:栈空间和可读性的实际权衡
递归写法简洁,但深度为 n 时必然消耗 O(n) 栈空间;迭代是 O(1) 空间。不过现代编译器对尾递归优化有限,C++ 标准不保证优化,所以别指望递归版能自动转成迭代。
使用场景差异:
- 链表长度可能上千?选迭代,避免栈溢出(尤其嵌入式或限制栈大小环境)
- 面试手写代码?递归更易一次写对逻辑,但得主动说明空间代价
- 需要原地反转且不允许额外容器?两者都满足,但递归隐式用了栈——这不算“额外容器”但算“额外空间”
反转后访问崩溃?检查 head 是否为空和 next 是否已置空
最常被忽略的点:反转操作本身不改变原 head 变量的值,但它的 next 字段已被修改。如果反转后还拿旧 head 当头去遍历,会直接跳到原第二个节点,漏掉新头节点;更糟的是,若忘了在递归版里写 head->next = nullptr,遍历时会无限循环。
调试建议:
- 反转后立刻打印新头节点的
val和next,确认非空且指向正确 - 用小样例(如
[1,2])手动走一遍指针变化,比看代码更快定位断点 - 注意 LeetCode 测试用例包含
head = nullptr,别假设输入总有节点










