迭代法用三指针(prev、curr、next)逐个反转,须先保存next防断裂;递归法让子链返回新头,再将当前节点接至其尾(head->next->next=head),二者均需更新头指针。

迭代法反转链表:三指针是核心,别漏掉 next 临时保存
迭代法本质是逐个调整每个节点的 next 指针方向,关键在于用三个指针协作:当前节点 curr、前驱节点 prev、以及必须提前保存的下一个节点 next。漏掉 next 保存会导致链表断裂,这是最常踩的坑。
典型错误现象:curr = curr->next 写在 curr->next = prev 之后,此时 curr->next 已被改写,原后续链丢失。
- 初始化:
prev = nullptr,curr = head - 循环中顺序固定:先
next = curr->next,再curr->next = prev,最后prev = curr; curr = next - 循环结束时
curr为nullptr,返回prev(即新头节点)
递归法反转链表:理解“子问题返回的是新尾,你要接在它后面”
递归法不是靠层层修改指针,而是让递归调用返回已反转好的子链表头,然后把当前节点“挂到”该子链表的末尾。难点在于:每次递归返回的其实是**新链表的头**,但你需要操作的是**新链表的尾**——而这个尾,恰好就是原链表的下一个节点(即 head->next)。
常见错误现象:试图直接改 newHead->next = head,但 newHead 是子链表头,不是尾;正确做法是 head->next->next = head,再断开 head->next = nullptr。
立即学习“C++免费学习笔记(深入)”;
- 递归终止条件:
head == nullptr || head->next == nullptr,返回head - 递归调用后拿到
newHead(子链表新头),执行:head->next->next = head和head->next = nullptr - 最后返回
newHead,全程不改变其值
迭代 vs 递归:空间开销和边界处理差异明显
迭代法空间复杂度是 O(1),无栈溢出风险,适合长链表;递归法空间复杂度是 O(n),深度为链表长度,对超长链表可能栈溢出。两者时间复杂度都是 O(n)。
边界场景要单独验证:
- 空链表(
head == nullptr):两种方法都应直接返回nullptr - 单节点链表(
head->next == nullptr):迭代法循环不执行,返回原head;递归法命中终止条件,也返回原head - 两节点链表:最容易暴露指针错位,建议手画图走一遍
next和next->next的指向
反转后原 head 不再是头,记得更新头指针
无论哪种方法,函数返回的都是新链表的头节点。如果你在调用处仍用原来的 head 变量访问链表,会得到错误结果或崩溃——因为 head 此时已是尾节点,且其 next 为 nullptr。
实操中容易忽略这点:
- 调用后必须重新赋值:
head = reverseList(head); - 如果函数参数是
ListNode*& head引用,可在内部直接更新,但需明确接口设计意图 - 调试时可用
printList(head)验证反转结果,别只看返回值是否非空
递归里那句 head->next->next = head 看似绕,其实就是在把“当前节点”塞进已反转子链的尾巴,这个视角卡住就容易写反。










