中序遍历二叉树全过程图解

news2024/9/23 6:50:27

文章目录

  • 中序遍历图解
  • 总结
  • 拓展:回归与回溯

中序遍历图解

在这里插入图片描述

首先看下中序遍历的代码,其接受一个根结点root作为参数,判断根节点是否为nil,不为nil则先递归遍历左子树。

func traversal(root *TreeNode,res *[]int)  {
    if root == nil {return}

    traversal(root.Left,res)
    *res = append(*res,root.Val)
    traversal(root.Right,res)
}

我们把树根结点A传递给它,其左结点为B,右结点为C

首先我们要检查root是否为nil,其不为nil,通过递归继续遍历左边的子树,将左子树传递给递归函数,该层递归函数的rootB,其左子树为D 右子树为E,判断root是否为nilroot不为nil,继续将该树的左子树向下递归,该层递归函数的rootD,左右子树都为nil,我们检查root是否为nilrootD,不为nil,继续递归遍历D的左子树,其左子树为nil,所以该层递归函数的rootnil满足递归结束条件,执行return退出该层递归函数

到此处时的运行栈如下图所示
在这里插入图片描述

此时的return会回到rootD的递归层,D的左子树已经遍历完毕,我们执行下一行语句append
该语句会将root的数据域加入到结构列表res中,即访问到了D,如下图
在这里插入图片描述

按照顺序继续执行,接下来将使用递归遍历D的右子树,这里D的右子树为nil,所以我们传入的递归参数也为nil,检测到rootnil,我们退出该层递归函数,回到调用层D,该层的所有语句都执行完毕了。我们继续回到调用它的函数,即B层的 traversal(root.Left,res)语句处

在这里插入图片描述

继续执行后序语句,执行 *res = append(*res,root.Val)记录root的数据域,即访问B,再执行下一条语句
递归访问B的右子树,将E传递给它,判断root是否为nilrootE,不为nil,递归调用E的左子树,左子树为nil,判断root是否为nil,为nil,退出该层
在这里插入图片描述
执行下一行,将E记录到结果中,继续遍历E的右子树,右子树为nil,直接退出该层递归函数,返回到了E的递归层,E这层也执行完毕了,返回到调用它的B
在这里插入图片描述

随即B层也执行完了,返回到调用它的A层 ,在该层执行下一行代码,将A记录到结果中,继续遍历A的右子树,A的右子树为C,其不为nil,递归C的左子树FF不为nil,递归F的左子树,F的左子树为nil,即传入的rootnil,满足递归结束条件,开始回归上层。
在这里插入图片描述

返回到调用它的F层,将F记录到结果中。遍历F的右子树,F的右子树也为nil,退出该层,到此F这层函数执行完毕,返回到调用F的递归层 C,下一行语句记录C
在这里插入图片描述

继续下一行语句,递归C的右子树G,判断该层递归的root是否为nil,当前rootG,不为nil,递归G的左子树,左子树为nil,满足递归结束条件,返回到调用它的G,输出G,递归G的右子树,右子树为nil
满足递归结束条件,返回到调用它的GG这层函数结束,返回上层到C

C也运行完毕,返回上层到AA也运行完毕,此该树递归结束,这样我们就得到了中序遍历序列

总结

再次回顾一下代码

func traversal(root *TreeNode,res *[]int)  {
    if root == nil {return}

    traversal(root.Left,res)
    *res = append(*res,root.Val)
    traversal(root.Right,res)
}

从我们的遍历全流程图解来看,不难理解,每个节点都是将其左子树全部递归遍历完后,才开始遍历其右子树的,如根节点A,是将其左子树BDE全部遍历完后,才开始遍历右子树的,注意思考递归栈哦,这样才能真正的理解。

中序遍历理解后,前序和后续遍历是一样的道理。这时一起看下后续遍历的代码:

func traversal(root *TreeNode,res *[]int)  {
    if root == nil {return}
    
    traversal(root.Left,res)
    traversal(root.Right,res)
     *res = append(*res,root.Val)
}

很多同学看到递归左右子树的那两行代码,很容易陷入误区,以为那两行是"同时"在执行,认为遍历完root的左节点后,立马遍历了其右节点,这种理解是非常不对的,实际是遍历完整个左子树后,经过回到当前层,此时才会开始执行当前层的traversal(root.Right,res)语句去遍历右子树。

尤其是看到两条回溯语句写在同一行时会更容易误解,如力扣104. 二叉树的最大深度

/**
 * definition for a binary tree node.
 * type treenode struct {
 *     val int
 *     left *treenode
 *     right *treenode
 * }
 */
func max (a, b int) int {
    if a > b {
        return a
    }
    return b
}

// 递归
func maxdepth(root *treenode) int {
    if root == nil {
        return 0
    }
    return max(maxdepth(root.left), maxdepth(root.right)) + 1
}

实际最后一行代码是简化版,等价于如下代码

/**
 * definition for a binary tree node.
 * type treenode struct {
 *     val int
 *     left *treenode
 *     right *treenode
 * }
 */
func max (a, b int) int {
    if a > b {
        return a
    }
    return b
}

// 递归
func maxdepth(root *treenode) int {
    if root == nil {
        return 0
    }
    leftDepth := maxdepth(root.left) // 递归左子树的深度
    rightDepth := maxdepth(root.right) // 递归右子树的深度
    
    return max(leftDepth,rightDepth ) + 1 // 当前根节点到叶子节点的最大深度
}

此时再看此代码是不是好理解一些 ,它就是我们的后序遍历哇!将左子树全部遍历完后,才会开始遍历右子树,最后则是根节点,然后回到上层调用栈,直到所有接地那遍历完毕,递归函数执行完毕。

拓展:回归与回溯

这里就是一个简介,详细可见:LeetCode 257. 二叉树的所有路径(回溯详解)

前序遍历以及回溯的过程如图:

回溯和递归中回归的区别:
回溯:因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。
回归:下层函数栈执行完成后,回归到上层函数栈来

实际上,回溯和回归都是伴随递归出现的,只是回溯比回归多了一个路径回退的操作。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2156919.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Tomcat中间件常见漏洞复现

#1.CVE-2017-12615 -----Tomcat put方法任意文件写入漏洞 1.打开靶场 cd vulhub/tomcat/CVE-2017-12615 docker-compose up -d docker ps 2.访问8080端口,来到靶场 3.首页进抓包,Tomcat允许适⽤put⽅法上传任意⽂件类型,但不允许jsp后缀…

redisson 延迟队列实现任务过期监听

一、需求: 任务超过一个小时以后,如果还为待执行状态,则自动转为结束状态。 二、实现: 创建延迟队列的监听任务RedisDelayedQueueListener,消费延迟队列;创建新增延迟队列的类,用于创建延迟队列&#xf…

LeetCode 热题 100 回顾17

干货分享,感谢您的阅读!原文见:LeetCode 热题 100 回顾_力code热题100-CSDN博客 一、哈希部分 1.两数之和 (简单) 题目描述 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标…

HTML翻牌器:用CSS和HTML元素创造动态数字展示

HTML翻牌器:用CSS和HTML元素创造动态数字展示 前言 翻牌器是一种数字动态展示形式,在生活中常见的例如翻牌计分、翻牌时钟等。 之所以以翻牌的形式是因为其物理设计的原因使其只能滚动翻牌展示数字,在电子显示设备不普及时,使用…

PMBOK® 第六版 估算活动持续时间

目录 读后感—PMBOK第六版 目录 在项目管理中,尤其是在软件开发这样的复杂项目中,工作内容是多种多样的。从需求分析、设计、编码到测试和部署,每个阶段都有其独特的挑战和不确定性。 没有人能独自完成所有估算工作并做到绝对精准。估算涉及…

【Unity Shader】Special Effects(九)Vortex 旋涡(UI)

源码:[点我获取源码] 索引 Vortex 旋涡思路分析旋涡中心旋涡旋转旋涡强度旋涡动画Vortex 旋涡 旋涡效果可以将一张图像以指定点作为旋涡中心,呈顺时针旋涡动画效果,使用动画播放器: 思路分析 首先,旋涡特效的核心也即是旋转(特别是uv坐标的旋转); 在此基础上,旋涡中…

Vue(15)——组合式API②

生命周期函数 选项式组合式beforeCreate/createdsetupbeforeMountonBeforeMount mountedonMounedbeforeUpdateonBeforeUpdateupdatedonUpdatedbeforeUnmountonBeforeUnmountunmountedonUnmounted 父子通信 父传子基本思想: 父组件中给子组件绑定属性…

Vue Devtools -----一条龙安装教程 + 解决安装使用过程的一些问题

一条龙安装教程(首次 安装看这里) 点击下方网址 进入下载页面 安装 |Vue 开发工具 (vuejs.org)https://devtools-v6.vuejs.org/guide/installation.html 选择适合自己浏览器的版本 以Edge为例,点击下载即可 我以为已经下载过了,…

BUUCTF-MISC-数据包中的线索

下载题目文件,解压发现是一段流量包 使用Wireshark打开 首先过滤HTTP数据流 然后追踪HTTP数据流 通过追踪数据流可以发现 流7 当中有一段base64编码,我们尝试解码 base64基本特征 Base64编码只包含64个字符:大写字母(A-Z&#x…

计算机网络笔记002

### 课堂讨论对话 **学生A**: 老师,计算机网络的组成是怎样的?🤔 **老师**: 非常好的问题!计算机网络主要由硬件、软件和通信协议三部分组成。我们先从硬件开始讨论吧。 **学生B**: 硬件包括哪些设备呢?&#x1f60…

cmd快速进入文件夹目录下

首先,将文件夹直接点击左键拖动至cmd窗口中,就可以得到目录路径。 还有就是,在命令行直接敲入D:或者C:就可以在磁盘之间进行转换,注意冒号不要丢。 再有,如果进入某磁盘中的一个文件夹,使用cd命令。路径获取…

zabbix email 告警

配置媒介、触发器动作(动作、操作) 为用户 定义媒体,比如电子邮件地址 动作 - 条件

[图解]静态关系和动态关系

1 00:00:01,060 --> 00:00:04,370 首先我们来看静态关系和动态关系 2 00:00:06,160 --> 00:00:10,040 我们要尽量基于静态关系来建立动态关系 3 00:00:11,740 --> 00:00:13,740 不能够在没有这个的基础上 4 00:00:14,220 --> 00:00:17,370 没有这个的情况下就胡…

2024PHP彩虹工具网源码一个多功能工具箱程序支持72种常用站长和开发等工具

安装: PHP>7.4 伪静态设置Thinkphp 设置/public为网站运行目录 访问你的域名/install进行安装即可 安装扩展 sg11 ,fileinfo , ionCube 常用功能 站长工具:ICP备案查询、IP地址查询、域名Whios查询、腾讯域名拦截查询、Mysql…

828华为云征文 | 构建高效搜索解决方案,Elasticsearch Kibana的完美结合

前言 构建高效搜索解决方案,FlexusX服务器与Elasticsearch & Kibana的完美结合,为企业带来云端搜索新体验。FlexusX实例以其卓越性能与灵活扩展性,确保高并发搜索的流畅运行。部署Elasticsearch,享受分布式搜索的精准与快速&a…

从Yargs源码学习中间件的设计

yargs中间件介绍 yargs 是一个用于解析命令行参数的流行库,它能帮助开发者轻松地定义 CLI(命令行接口),并提供参数处理、命令组织、help文本自动生成等功能。今天我们来学习一下它对中间件的支持。 中间件的API详细信息&#xff0…

Python | Leetcode Python题解之第430题扁平化多级双向链表

题目: 题解: class Solution:def flatten(self, head: "Node") -> "Node":def dfs(node: "Node") -> "Node":cur node# 记录链表的最后一个节点last Nonewhile cur:nxt cur.next# 如果有子节点&#…

旋转机械故障数据集 全网首发

旋转机械故障 数据集 11G资料 泵、齿轮箱、电机、流量、液压系统、轴承(西储大学、辛辛那提大学、FEMTO、MOSFET)、PHM08挑战数据集、我闪发动机降级模拟数据集、铣床等 旋转机械故障数据集 数据集描述 该数据集是一个综合性的旋转机械故障检测和诊断数据集,旨在…

【ChatGPT】提示词助力广告文案、PPT制作与书籍推荐的高效新模式

博客主页: [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 💯前言💯高效广告推销文案提示词使用方法 💯AI自动生成PPT全流程提示词使用方法 💯精选书籍推荐爆款文案提示词使用方法 💯小结 💯…

【VUE3.0】动手做一套像素风的前端UI组件库---Radio

目录 引言做之前先仔细看看UI设计稿解读一下都有哪些元素:参考下成熟的组件库,看看还需要做什么? 代码编写1. 设计group包裹选项的组件group.vueitem.vue 2. 让group的v-model和item的value联动起来3. 完善一下item的指示器样式4. 补充禁用模…