golang实现单向链表反转
方法1:迭代法(推荐)
时间复杂度 O(n),空间复杂度 O(1)
实现步骤:
- 定义三个指针:
prev(前驱节点)、current(当前节点)、next(后继节点)。 - 遍历链表,逐个反转节点的指向。
- 最终
prev成为新链表的头节点。
迭代法通过遍历原始链表,逐个将节点的指针指向其前一个节点,从而反转链表。
package main
import (
"fmt"
)
// ListNode 定义链表节点
type ListNode struct {
Val int
Next *ListNode
}
// reverseList 迭代法反转链表
func reverseList(head *ListNode) *ListNode {
var prev *ListNode = nil
curr := head
for curr != nil {
nextTemp := curr.Next // 保存当前节点的下一个节点
curr.Next = prev // 反转当前节点的指针
prev = curr // prev向前移动
curr = nextTemp // curr向前移动
}
return prev // 当curr为nil时,prev即为新的头节点
}
func main() {
// 创建链表 1 -> 2 -> 3 -> 4 -> 5
list := &ListNode{Val: 1}
list2 := &ListNode{Val: 2}
list.Next = list2
list3 := &ListNode{Val: 3}
list2.Next = list3
list4 := &ListNode{Val: 4}
list3.Next = list4
list5 := &ListNode{Val: 5}
list4.Next = list5
reversedList := reverseList(list)
/*for curr := reversedList; curr != nil; curr = curr.Next {
fmt.Printf("%d ", curr.Val) // 输出反转后的链表:5 4 3 2 1
}*/
curr := reversedList
for {
if curr != nil {
fmt.Printf("%d ", curr.Val) // 5 4 3 2 1
curr = curr.Next
} else {
fmt.Println("\n输出完成")
return
}
}
}
方法2:递归法
时间复杂度 O(n),空间复杂度 O(n)(递归栈深度)
实现步骤:
- 基线条件:链表为空或只有一个节点时,直接返回头节点。
- 递归反转后续链表,并将当前节点连接到反转后的链表尾部。
递归法通过递归调用自身来实现反转,每次递归都将当前节点作为新的头节点返回,并逐步构建反转后的链表。
package main
import "fmt"
// ListNode 定义链表节点
type ListNode struct {
Val int
Next *ListNode
}
// reverseListRecursively 递归法反转链表
func reverseListRecursively(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head // 空链表或只有一个节点的链表直接返回自身作为新头节点
}
newHead := reverseListRecursively(head.Next) // 递归调用,反转剩余部分并获取新的头节点
head.Next.Next = head // 将当前节点的下一个节点指向当前节点,实现反转
head.Next = nil // 将当前节点的下一个节点置为nil,防止成环
return newHead // 返回新的头节点
}
func main() {
// 创建链表 1 -> 2 -> 3 -> 4 -> 5
list := &ListNode{Val: 1}
list2 := &ListNode{Val: 2}
list.Next = list2
list3 := &ListNode{Val: 3}
list2.Next = list3
list4 := &ListNode{Val: 4}
list3.Next = list4
list5 := &ListNode{Val: 5}
list4.Next = list5
reversedList := reverseListRecursively(list)
/*for curr := reversedList; curr != nil; curr = curr.Next {
fmt.Printf("%d ", curr.Val) // 输出反转后的链表:5 4 3 2 1
}*/
curr := reversedList
for {
if curr != nil {
fmt.Printf("%d ", curr.Val) // 5 4 3 2 1
curr = curr.Next
} else {
fmt.Println("\n输出完成")
return
}
}
}
关键点总结
- 迭代法:通过三指针直接修改节点指向,无需额外空间,适合处理长链表。
- 递归法:代码简洁,但递归深度与链表长度正相关,可能引发栈溢出。
- 选择建议:优先使用迭代法,递归法仅用于理解递归思想或短链表场景。
两种方法各有优缺点,迭代法在空间复杂度上更优(只使用常量空间),而递归法在实现上更为简洁直观。可以根据具体需求和偏好选择使用哪一种方法。

浙公网安备 33010602011771号