链表反转必须用指针(Node)而非值传递,因Go中结构体参数为值传递,拷贝后修改Next不影响原链表;Next字段类型必须为Node,递归/迭代均需传入并返回*Node,且需正确处理nil、单节点等边界。

为什么链表反转必须用指针,而不是值传递
Go 里函数参数是值传递,Node 结构体传进去就拷贝一份,改它不影响原链表。想真正翻转物理连接,必须操作原始节点的 Next 字段地址——也就是传 *Node。
常见错误是写成 func reverse(head Node) Node,跑完发现链表没变,因为只是在副本上倒腾指针。
- 结构体定义里
Next字段类型必须是*Node,不是Node - 递归或迭代入口都得接收
*Node,返回值也应是*Node - 如果传入
nil,直接返回nil,别解引用
迭代法反转:三个指针怎么不绕晕
核心是维护 prev、curr、next 三者关系,每轮把 curr.Next 指向 prev,再整体前移。容易错在顺序不对导致链表断裂。
关键步骤顺序不能换:
立即学习“go语言免费学习笔记(深入)”;
- 先用
next = curr.Next保存下一个节点(否则改完curr.Next就找不到了) - 再执行
curr.Next = prev - 最后更新
prev = curr和curr = next
示例片段:
func reverseIterative(head *Node) *Node {
var prev *Node
curr := head
for curr != nil {
next := curr.Next
curr.Next = prev
prev = curr
curr = next
}
return prev
}
递归法反转:谁才是新头节点
递归到底层时,head.Next == nil 的那个节点就是反转后的头,要一路透传回来。中间层的任务是让「自己」的 Next 指向「自己」,然后断开原来的方向。
容易漏掉的关键点:
- 递归终止条件是
head == nil || head.Next == nil,后者必须有,否则空链表或单节点会 panic - 拿到
newHead := reverseRecursive(head.Next)后,要执行head.Next.Next = head,不是newHead.Next = head - 必须加
head.Next = nil,否则会留下环(比如 1→2→1)
示例片段:
func reverseRecursive(head *Node) *Node {
if head == nil || head.Next == nil {
return head
}
newHead := reverseRecursive(head.Next)
head.Next.Next = head
head.Next = nil
return newHead
}
反转后要注意的边界和兼容性
反转本身不涉及内存分配,性能 O(n),但实际使用中几个地方容易出问题:
- 如果链表带环,反转会陷入死循环——务必先确认无环,或加计数/快慢指针检测
- 多个 goroutine 并发读写同一链表时,反转过程不是原子的,需加
sync.Mutex或改用 channel 管理所有权 - 若节点含其他指针字段(如
Prev),只改Next会导致双向链表逻辑错乱 - 测试时别只用
1→2→3,一定要试nil、单节点、两个节点这三种边界
最常被跳过的一步:反转后原 head 变成了尾节点,Next 是 nil,但代码里如果还拿着旧变量继续操作,容易误以为链表没变。










