单向链表原地逆序最高效方式是三指针迭代法:prev指向已处理节点(初为nullptr),curr指向当前节点(初为head),next临时保存curr->next;更新顺序必须为next=curr->next→curr->next=prev→prev=curr→curr=next;需判空并返回prev。

用三个指针原地反转,别申请新节点
单向链表逆序最常用、最高效的方式是三指针迭代法:只改 next 指针指向,不分配新节点,时间 O(n),空间 O(1)。关键不是“怎么写循环”,而是搞清三指针各自职责和更新顺序——错一步就断链或死循环。
常见错误现象:nullptr 解引用崩溃、反转后只剩头节点、链表变环(head->next == head)、漏掉最后一个节点。
-
prev:始终指向上一个已处理好的节点(初始为nullptr) -
curr:当前正在处理的节点(初始为head) -
next:临时保存curr->next,防止反转后丢失后续节点
更新顺序必须是:next = curr->next → curr->next = prev → prev = curr → curr = next。少一个临时变量或调换顺序,立刻出问题。
递归写法简洁但有栈溢出风险
递归本质是把“先走到尾,再回头改指针”压进调用栈,代码短但实际不推荐用于长链表。它的核心逻辑是:递归调用返回的是已反转的子链表头,然后把原头节点接到该子链表尾。
立即学习“C++免费学习笔记(深入)”;
使用场景:教学演示、链表长度明确很短(比如 ≤ 1000)、或面试时快速写出逻辑框架。
性能影响:每层递归消耗栈空间,链表长度 n 超过系统默认栈限制(通常几 MB)就会 Segmentation fault 或 stack overflow。g++ 默认栈大小约 8MB,对应约 10⁵ 级节点——但保守起见,超过 10⁴ 就该警惕。
示例关键行:ListNode* newHead = reverseList(curr->next); → curr->next->next = curr; → curr->next = nullptr;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
反转前必须判空,否则 curr->next 直接崩
所有实现都必须在开头检查 head == nullptr 或 head->next == nullptr。漏掉前者会导致空指针解引用;漏掉后者会让单节点链表进入循环体,虽然可能不崩,但逻辑冗余且易掩盖边界问题。
常见错误写法:while (curr) 却没提前处理空链表,导致 curr->next 在第一轮就非法访问。
正确守门姿势:
if (!head || !head->next) {
return head;
}这个判断不是可有可无的防御性编程,而是算法逻辑成立的前提——反转操作至少需要两个有效节点才能“交换指向”。
反转后记得更新头指针,否则外部还在用旧地址
原地反转不改变节点内存位置,只改 next,所以最终要返回新的头——也就是原链表的尾节点。迭代法中它是 prev;递归法中它是递归最深层返回的那个节点。
容易踩的坑:return head; 写成固定返回原 head,结果调用方拿到的仍是旧头,而它现在是尾,next 为 nullptr,整条链看起来“只剩一个节点”。
务必确认返回值:
迭代版末尾是 return prev;,不是 curr(此时 curr 已为 nullptr);
递归版最后一行必须是 return newHead;,不能漏掉或写错变量名。
真正麻烦的从来不是算法本身,而是谁持有这个新头——如果链表封装在类里,还要同步更新类成员 m_head,否则外部接口仍指向旧头。

















