golang实现单向链表反转

方法1:迭代法(推荐)

时间复杂度 O(n),空间复杂度 O(1)

实现步骤

  1. 定义三个指针:prev(前驱节点)、current(当前节点)、next(后继节点)。
  2. 遍历链表,逐个反转节点的指向。
  3. 最终 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)(递归栈深度)

实现步骤

  1. 基线条件:链表为空或只有一个节点时,直接返回头节点。
  2. 递归反转后续链表,并将当前节点连接到反转后的链表尾部。

递归法通过递归调用自身来实现反转,每次递归都将当前节点作为新的头节点返回,并逐步构建反转后的链表。

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
		}
	}
}

关键点总结

  • 迭代法:通过三指针直接修改节点指向,无需额外空间,适合处理长链表。
  • 递归法:代码简洁,但递归深度与链表长度正相关,可能引发栈溢出。
  • 选择建议:优先使用迭代法,递归法仅用于理解递归思想或短链表场景。

两种方法各有优缺点,迭代法在空间复杂度上更优(只使用常量空间),而递归法在实现上更为简洁直观。可以根据具体需求和偏好选择使用哪一种方法。

posted @ 2025-03-04 21:34  搁浅~浅浅浅  阅读(49)  评论(0)    收藏  举报