三指针迭代法反转单链表最稳妥:用prev、curr、next依次推进,先保存next再修改指针,空间复杂度o(1),避免栈溢出;递归法需谨慎处理边界和断链,易因未置空head->next成环。

用三指针迭代法反转单链表,最稳
直接上手就写递归?容易栈溢出,也难调试。C++里反转单链表,首选三指针迭代——prev、curr、next三个变量轮着换,逻辑清晰,空间复杂度 O(1),而且不依赖编译器优化。
常见错误是把 next 提前改了,导致链表断掉再也找不回后续节点:
- 错:先执行
curr->next = prev,再取next = curr->next→ 此时next已经是prev,不是原后续节点 - 对:必须先用临时变量存好
next = curr->next,再改指针,最后推进
典型写法:
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr != nullptr) {
ListNode* next = curr->next; // 先保命
curr->next = prev; // 再翻转
prev = curr; // 推进 prev
curr = next; // 推进 curr
}
return prev; // 新头结点
}递归写法能用,但得盯住边界和栈深度
递归本质是靠系统栈记住“翻转完后面,再把当前节点接在末尾”,简洁但有隐患。最常崩在空链表或单节点没处理好,或者输入太长(比如十万级节点)直接栈溢出。
立即学习“C++免费学习笔记(深入)”;
关键点:
- 递归终止条件必须覆盖
head == nullptr和head->next == nullptr - 递归调用后,
head->next->next = head这句不能漏,否则链没连回来 -
head->next = 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;
}反转前确认节点定义和内存管理方式
很多崩溃不是算法错,是 ListNode 定义不一致或手动 new/delete 混乱。比如:
- LeetCode 默认用堆上分配的节点,你本地测试如果用栈变量(
ListNode node;),反转后返回指针就是悬垂指针 - 自己写的链表若带
std::unique_ptr,就不能直接操作next原始指针,得用release()和reset() - 反转后别忘了原
head已失效,继续访问head->next是未定义行为
安全起见,统一用原始指针 + 手动管理,或全程用智能指针并严格遵循移动语义。
性能差异不大,但迭代法更容易嵌入实际工程场景
两种方法时间都是 O(n),但迭代法没有函数调用开销,也不受栈限制,在嵌入式、游戏逻辑、高频调用路径中更可靠。
如果你要反转的是带额外字段(如 size、tail 指针)的封装链表类,迭代法也更容易同步更新这些元信息;递归则需额外传参或用成员变量暂存,反而绕远。
真正容易被忽略的是:反转后,原头结点变成尾结点,它的 next 必须设为 nullptr —— 不然遍历时可能跑飞,尤其在循环检测或调试打印时突然多出一截旧链。









