迭代法用prev、curr、next三指针,先保存next再反转,返回prev;递归法以子链表新头为返回值,需断原链并重连,注意空指针与成环。

用迭代法反转单链表:三指针是核心
迭代反转的关键在于维护三个指针:prev、curr、next,避免在修改 curr->next 时丢失后续节点。常见错误是先改 curr->next 再取 next,导致链表断裂。
适用场景:空间受限、链表很长、需稳定 O(1) 额外空间。
-
prev初始为nullptr,表示新链表的尾(即原链表反转后的头的前驱) - 每次循环前必须先保存
curr->next到next,再执行curr->next = prev - 最后返回
prev,不是curr(此时curr已为nullptr)
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; // 新头节点
}
用递归法反转单链表:理解“子问题返回的是新头”
递归写法简洁,但容易误解返回值含义——reverseList(head->next) 返回的是以 head->next 为起点的子链表反转后的**新头节点**,不是原尾节点。常见错误是试图用递归函数直接操作 head 的 next 而忽略断链与重连顺序。
立即学习“C++免费学习笔记(深入)”;
- 递归终止条件是
head == nullptr || head->next == nullptr,后者保证至少有一个节点可返 - 递归调用后,
head->next已指向新链表尾部,需让head->next->next = head完成翻转 - 必须置
head->next = nullptr,否则形成环(尤其原链表长度 ≥ 2 时)
ListNode* reverseList(ListNode* head) {
if (!head || !head->next) return head;
ListNode* newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
}
反转过程中容易踩的坑:空指针与环检测
两类错误高频出现:一类是未判空就访问 head->next 或 curr->next,触发段错误;另一类是忘记置 head->next = nullptr 或误写成 curr->next = prev 顺序颠倒,导致反转后链表成环,遍历时无限循环。
- 迭代中若省略
curr != nullptr判断,curr->next在curr为nullptr时崩溃 - 递归中若只写
if (!head) return head;,漏掉!head->next,则单节点输入会进入递归并尝试解引用空指针 - 反转后建议加简单验证:遍历新链表,检查是否恰好
size个节点且无重复地址
性能与实际选型建议:别迷信递归简洁性
迭代时间 O(n)、空间 O(1),递归时间 O(n)、空间 O(n)(系统栈深度)。当链表长度超过几千时,递归可能栈溢出(取决于编译器和栈大小),而迭代完全无此风险。
- LeetCode 等平台测试用例常含长度 10⁵ 的链表,递归在此类场景下不可靠
- 如果必须用递归(如教学演示),可用尾递归优化写法(但 C++ 标准不保证优化,且需手动改写)
- 真实项目中,除非有明确架构约束,否则默认选迭代实现
真正要注意的不是“怎么写”,而是“什么时候不该用递归”——尤其当输入规模不可控时,空指针检查和栈深度都得算进设计里。











