从尾到头打印链表的两种Go实现方法解析

从尾到头打印链表的两种Go实现方法解析

awesome-golang-algorithm :memo: LeetCode of algorithms with golang solution(updating). awesome-golang-algorithm 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-golang-algorithm

前言

链表是一种常见的基础数据结构,在算法面试和实际开发中经常遇到。本文将详细解析如何使用Go语言实现"从尾到头打印链表"这一经典问题,并比较两种不同解法的优缺点。

问题描述

给定一个链表的头节点,要求从尾到头反过来返回每个节点的值(用数组返回)。

示例: 输入:head = [1,3,2] 输出:[2,3,1]

方法一:递归解法

算法思路

递归是一种自然而直观的解决链表问题的方法。对于从尾到头打印链表,我们可以利用递归的"后进先出"特性:

  1. 递归到链表末尾
  2. 在回溯过程中收集节点值
  3. 最终得到的就是反转后的节点值序列

复杂度分析

  • 时间复杂度:O(N),需要遍历链表中的每个节点
  • 空间复杂度:O(N),递归调用栈的深度等于链表长度

Go实现代码

func reversePrint(head *ListNode) []int {
    ans := make([]int, 0)
    if head == nil {
        return ans
    }
    ans = reversePrint(head.Next)
    ans = append(ans, head.Val)
    return ans
}

代码解析

  1. 首先创建一个空切片ans用于存储结果
  2. 递归终止条件:当前节点为nil时返回空切片
  3. 递归调用reversePrint(head.Next)先处理下一个节点
  4. 在回溯阶段将当前节点的值追加到切片末尾
  5. 最终返回收集好的结果切片

方法二:迭代反转链表法

算法思路

这种方法通过迭代方式反转链表,然后顺序遍历反转后的链表收集节点值:

  1. 使用三个指针(pre, cur, next)反转链表
  2. 遍历反转后的链表收集节点值
  3. 返回结果数组

复杂度分析

  • 时间复杂度:O(N),需要遍历链表两次(反转一次,收集一次)
  • 空间复杂度:O(N),需要存储结果数组

Go实现代码

func reversePrint(head *ListNode) []int {
    if head == nil {
        return []int{}
    }
    pre, cur, next, ans := &ListNode{}, head, head.Next, []int{}
    for cur != nil {
        next = cur.Next
        cur.Next = pre
        pre = cur
        cur = next
    }
    for pre.Next != nil {
        ans = append(ans, pre.Val)
        pre = pre.Next
    }
    return ans
}

代码解析

  1. 初始化三个指针:pre(前驱)、cur(当前)、next(后继)
  2. 遍历链表,反转每个节点的Next指针指向
  3. 反转完成后,pre指向新链表的头节点
  4. 遍历反转后的链表,收集节点值到结果切片
  5. 返回结果切片

方法比较与选择

| 方法 | 优点 | 缺点 | 适用场景 | |------|------|------|----------| | 递归 | 代码简洁直观 | 栈空间开销大,可能栈溢出 | 链表长度不大时 | | 迭代 | 空间效率高 | 需要修改原链表结构 | 链表长度较大或不允许递归时 |

对于面试或实际开发,通常推荐递归方法,因为它更简洁且不需要修改原链表结构。但如果链表非常长,迭代方法更为稳妥。

扩展思考

  1. 如果要求不修改原链表结构,迭代法该如何实现?

    • 可以使用栈结构辅助,先顺序遍历链表压栈,再出栈收集结果
  2. 如何优化递归方法的空间复杂度?

    • 可以预先计算链表长度,初始化结果切片为固定大小,然后从后向前填充
  3. 在实际工程中,哪种方法更常用?

    • 递归方法更为常见,除非有明确的性能要求或链表长度可能非常大的情况

总结

本文详细分析了从尾到头打印链表的两种Go语言实现方法。递归方法简洁优雅,适合大多数情况;迭代方法虽然稍显复杂,但在特定场景下更为可靠。理解这两种方法的实现原理和适用场景,有助于我们在面对类似链表问题时做出合理的选择。

awesome-golang-algorithm :memo: LeetCode of algorithms with golang solution(updating). awesome-golang-algorithm 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-golang-algorithm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瞿格女

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值