当前位置: 首页 > news >正文

LeetCode 94. 二叉树的中序遍历

LeetCode 94. 二叉树的中序遍历

在这里插入图片描述
这是一道非常基础的模版题,因此就不放出题目描述及输入输出示例和数据范围了。

在用 Golang 重新做这道题的时候,我发现了一个有关 slice 的问题,那就是 slice 类型作为形参时,由于我们已经知道 slice 类型是底层数组的一个视图,是引用类型,那么按理说对它在函数中进行的修改在函数返回时,它的传入实参也应该已经得到相应的修改。

但事实却与预期不符,如果直接以 slice 作为形参,那么无法返回正确的中序遍历结果:

// ❌ 无法得到预期的结果
/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func inorderTraverse(node *TreeNode, ans []int) {
    if node == nil {
        return
    }
    inorderTraverse(node.Left, ans)
    ans = append(ans, node.Val)
    inorderTraverse(node.Right, ans)
}

func inorderTraversal(root *TreeNode) []int {
    ans := []int{}
    inorderTraverse(root, ans)
    return ans
}

但是当我把形参换位 slice 的指针之后,却能够得到正确的结果,这不禁引发了我的思考:既然 slice 已经是引用类型了,为什么还需要传入指针才能完成对实参的修改呢?

想要回答这个问题,我们需要首先回顾 Golang slice 的底层原理。Golang 的 slice 有三个字段,分别是 unsafe.Pointer,指向底层数组,以及 lencap,分别表示当前 slice 的长度以及容量。

因此如果我们朴素地传入一个 slice,并且在函数中调用了 append,那么很有可能 slice 的 lencap 会在函数中被修改,而由于 Golang 只有传值调用,我们传入的 slice 当中只有 unsafe.Pointer 字段指向底层数组的地址,但 lencap 字段是从函数外部通过调用复制进来的。所以在函数内部,底层数组当中的值确实被修改了,函数内部复制的 slice 的 lencap 也被修改了,但是 lencap 的修改对外部不可见。

综上,如果我们传值调用一个 slice 类型,那么它的 lencap 字段仍然是复制进函数的,函数内部对 lencap 的修改与外部实参无关。

所以如果我们想要使用 ans 这个 slice 保存正确的结果,应该传入 slice 的指针:

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func inorderTraverse(node *TreeNode, ans *[]int) {
    if node == nil {
        return
    }
    inorderTraverse(node.Left, ans)
    *ans = append(*ans, node.Val)
    inorderTraverse(node.Right, ans)
}

func inorderTraversal(root *TreeNode) []int {
    ans := []int{}
    inorderTraverse(root, &ans)
    return ans
}
http://www.dtcms.com/a/105195.html

相关文章:

  • PUSCH(Physical Uplink Shared Channel,物理上行共享信道)
  • 自动备份文件到服务器,自动备份文件到服务器有哪些方法?
  • SkyWalking+Springboot实战(最详细)
  • mysql 日期时间变成中文显示
  • 如何解决 Hive 在创建 MySQL 表时出现乱码???的问题
  • 堤坝决口快速沉箱,守护生命的抗洪防线|鼎跃安全
  • 《认知觉醒》下篇·第四章第二节“学习专注:深度沉浸是进化双刃剑的安全剑柄” 总结
  • Layui日期选择器的使用逻辑
  • 23种设计模式-结构型模式-装饰
  • 如何在 SwiftUI 视图中使用分页(Paging)机制显示 SwiftData 数据(三)
  • 藏族问候语语料库下载-选取按方言区分类的藏语问候语音频
  • 卷积层里的多输入多输出通道
  • 论文笔记:ASTTN模型
  • LINUX 1
  • [Linux实战] Linux设备树原理与应用详解
  • 并发多线程八股
  • ML 聚类算法 dbscan|| OPTICS
  • 使用 glog 库的 CHECK 宏进行条件断言和错误检测
  • K-均值聚类
  • DeepBI如何探索流量种子,快速帮助产品扩展流量
  • 卷积神经网络(CNN)原理与实战:从LeNet到ResNet
  • C 语 言 --- 整 形 提 升
  • 第三章 devextreme-react/scheduler 定制属性学习
  • 第十届MathorCup高校数学建模挑战赛-A题:无车承运人平台线路定价问题
  • Oceanbase企业版安装(非生产环境)
  • MAC使用当前VScode总是报权限不足的错误,简单修改
  • 【Linux内核系列】:文件ELF格式详解
  • TypeScript 中 await 的详解
  • 通用目标检测技术选型分析报告--截止2025年4月
  • 从零构建大语言模型全栈开发指南:第四部分:工程实践与部署-4.2.2多模态数据处理:图像编码与文本对齐(实战代码示例)