二叉树的前中后序遍历(迭代法)( 含leetcode上三道【前中后序】遍历题目)

文章目录

  • 前序遍历(迭代法)
  • 中序遍历(迭代法)
  • 后序遍历(迭代法)
  • 总结

为什么可以用迭代法(非递归的方式)来实现二叉树的前后中序遍历呢?

在队列与栈专题我们就感受到了,匹配问题都是栈的强项,而递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,这就是递归为什么可以返回上一层位置的原因

此时大家应该知道我们用栈也可以是实现二叉树的前后中序遍历了。

前序遍历(迭代法)

我们先看一下前序遍历。

前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。

为什么要先加入 右孩子,再加入左孩子呢? 因为这样出栈的时候才是中左右的顺序。

不难写出如下Go代码: (注意代码中空节点不入栈)

144. 二叉树的前序遍历

/*** Definition for a binary tree node.* type TreeNode struct {*     Val int*     Left *TreeNode*     Right *TreeNode* }*/
func preorderTraversal(root *TreeNode) []int {if root == nil {return []int{}}res := make([]int,0)// 二叉树的遍历(迭代法)依赖栈来辅助完成stack := make([]*TreeNode,0)stack = append(stack,root)// 初始时根节点已经入栈,后续栈不为空就可以一直遍历for len(stack) != 0 {// 栈弹出一个元素加入结果中curNode := stack[len(stack) - 1]stack = stack[0:len(stack) - 1]res = append(res,curNode.Val)// 先让右节点入栈,后让左节点入栈,这样出栈才会符合根左右if curNode.Right != nil {stack = append(stack,curNode.Right)}if curNode.Left != nil {stack = append(stack,curNode.Left)}}return res
}

在这里插入图片描述

此时会发现貌似使用迭代法写出前序遍历并不难,确实不难。

此时是不是想改一点前序遍历代码顺序就把中序遍历搞出来了?

其实还真不行!

但接下来,再用迭代法写中序遍历的时候,会发现套路又不一样了,目前的前序遍历的逻辑无法直接应用到中序遍历上。

中序遍历(迭代法)

为了解释清楚,我说明一下 刚刚在迭代的过程中,其实我们有两个操作:

  • 处理:将元素放进res数组中
  • 访问:遍历节点

分析一下为什么刚刚写的前序遍历的代码,不能和中序遍历通用呢,因为前序遍历的顺序是中左右,先访问的元素是中间节点,要处理的元素也是中间节点,所以刚刚才能写出相对简洁的代码,因为要访问的元素和要处理的元素顺序是一致的,都是中间节点。

那么再看看中序遍历,中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是再把节点的数值放进res数组中),这就造成了处理顺序和访问顺序是不一致的。

那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,当前指针向左边走到头的时候,说明左边遍历到底了,可以从栈弹出一个元素,即【左中右】,左边到底,栈中弹出【中】访问,而后遍历【右】,但是【右】又是一颗子树,继续往左走到头才行。

中序遍历,可以写出如下Go代码:

注意体会下面注释中的【遍历】和【访问】的区别

94. 二叉树的中序遍历

/*** Definition for a binary tree node.* type TreeNode struct {*     Val int*     Left *TreeNode*     Right *TreeNode* }*/
func inorderTraversal(root *TreeNode) []int {if root == nil {return []int{}}res := make([]int,0)stack := make([]*TreeNode,0)cur := root// 注意体会下面注释中的【遍历】和【访问】的区别for cur != nil || len(stack) != 0 {// 当前节点不为nil,说明左边没有走到头,继续往左遍历if cur != nil {stack = append(stack,cur)cur = cur.Left} else { // 当前节点为空还能来到这里,说明栈非空,栈顶就是当前要访问的元素cur = stack[len(stack) - 1]stack = stack[0:len(stack) - 1]// 当前访问的元素放入结果res = append(res,cur.Val)// 当前节点左边遍历完,当前节点也访问过了,即左中以完成,接下来访问当前节点的右子树cur = cur.Right}}return res
}

在这里插入图片描述

后序遍历(迭代法)

再来看后序遍历,先序遍历是中左右,后序遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转res数组,输出的结果顺序就是左右中了,如下图:
在这里插入图片描述

所以后序遍历只需要前序遍历的代码稍作修改就可以了,代码如下:

145. 二叉树的后序遍历

/*** Definition for a binary tree node.* type TreeNode struct {*     Val int*     Left *TreeNode*     Right *TreeNode* }*/
func postorderTraversal(root *TreeNode) []int {if root == nil {return []int{}}res := make([]int,0)stack := make([]*TreeNode,0)stack = append(stack,root)for len(stack) != 0 {cur := stack[len(stack) - 1]stack = stack[0:len(stack) - 1]res = append(res,cur.Val)if cur.Left != nil {stack = append(stack,cur.Left)}if cur.Right != nil {stack = append(stack,cur.Right)}}// 反转遍历的结果reverse(res)return res
}func reverse(arr []int) {i,j := 0,len(arr) - 1for i < j {arr[i],arr[j] = arr[j],arr[i]i++j--}return
}

在这里插入图片描述

总结

此时我们用迭代法写出了二叉树的前后中序遍历,大家可以看出前序和中序是完全两种代码风格,并不像递归写法那样代码稍做调整,就可以实现前后中序。

这是因为前序遍历中访问节点(遍历节点)和处理节点(将元素放进res数组中)可以同步处理,但是中序就无法做到同步!

上面这句话,可能一些同学不太理解,建议自己亲手用迭代法,先写出来前序,再试试能不能写出中序,就能理解了。

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

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

相关文章

KeyCode及KeyCode分发机制

文章目录 需求场景纯KeyCode 快捷操作KeyCode 按键响应操作、拦截 一、工作中常用KeyCode二、KeyCode大全三、KeyCode 响应事件事件输入流程事件响应源码分析源码举例说明 需求场景 纯KeyCode 快捷操作 经常在代码中实现返回、Home 、音量加减、截屏 等功能实现&#xff0c;代…

SpringBoot(40) — SpringBoot整合MyBatis-plus

前言 在上节中我们对MyBatis-plus特性有了一个整体的认识&#xff0c;然后也大致讲了些MyBatis与MyBatis-plus的不同之处。大家感兴趣的话&#xff0c;可参考以下文章 SpringBoot(39) — MyBatis-plus简介 这节我们来讲讲SpringBoot项目如何快速接入MyBatis-plus框架。 今天涉及…

开源网安多城联动、多形式开展网安周公益活动,传播网络安全知识

9月9日至15日&#xff0c;以“网络安全为人民&#xff0c;网络安全靠人民”为主题的2024年国家网络安全宣传周将在全国范围内统一开展&#xff0c;通过多样的形式、丰富的内容&#xff0c;助力全社会网络安全意识和防护技能提升。开源网安今年继续为各地企业、群众带来了丰富的…

BOE(京东方)领先科技赋能体育产业全面向新 以击剑、电竞、健身三大应用场景诠释未来健康运动新生活

巴黎全球体育盛会虽已闭幕&#xff0c;但世界范围内的运动热潮并未消退。9月12日&#xff0c;在北京恒通国际商务园&#xff08;UBP&#xff09;的之所ICC&#xff0c;BOE&#xff08;京东方&#xff09;开启了以“屏实力 FUN肆热爱”为主题的“科技赋能体育”互动体验活动。活…

esp32 wifi 联网后,用http 发送hello 用pc 浏览器查看网页

参考chatgpt Esp32可以配置为http服务器&#xff0c;可以socket编程。为了免除编写针对各种操作系统的app。完全可以用浏览器仿问esp32服务器&#xff0c;获取esp32的各种数据&#xff0c;甚至esp的音频&#xff0c;视频。也可以利用浏览器对esp进行各种操作。但esp不能主动仿…

vue3前端开发-小兔鲜超市-本地购物车列表页面的统计计算

vue3前端开发-小兔鲜超市-本地购物车列表页面的统计计算&#xff01;这一次&#xff0c;实现了一些本地购物车列表页面的&#xff0c;简单的计算。 代码如下所示&#xff1a; import { computed, ref } from vue import { defineStore } from pinia export const useCartStor…

web基础—dvwa靶场(八)SQL Injection(Blind)

SQL Injection(Blind)&#xff08;SQL注入之盲注&#xff09; SQL Injection(Blind)&#xff0c;SQL盲注&#xff0c;相比于常规的SQL注入&#xff0c;他不会将返回具体的数据信息或语法信息&#xff0c;只会将服务器包装后的信息返回到页面中。 常规SQL注入与SQL盲注详细对比…

css 样式简单学习(一)

目录 1. css 介绍 1.1 css 样式 1.2 css代码风格 1.2.1 书写格式 1.2.2 样式大小写​编辑 1.2.3 空格规范 2. 基础选择器 2.1 选择器的作用​编辑 2.2 选择器的分类 2.3 基础选择器 2.3.1 标签选择器​编辑 2.3.2 类选择器​编辑 2.3.3 类选择器-多类名​编辑 2.…

Unity 百度AI实现无绿幕拍照抠像功能(详解版)

目录 一、前言 1.抠像效果 2.去哪找百度ai抠图 3.基础流程跳过 二、获取AccessToken 1.什么是Token 2.为什么要获取Token 3.如何获取token 4.解析json 5.完整代码 三、抠像 1.准备地址 2.建立链接&#xff0c;和基本配置 3.图片格式转换 4.开始上传 5.获取回复…

python本地进程通讯----共享内存变量

背景 最近在开发实践中&#xff0c;接触到了需要多进程开发的场景。众所周知&#xff0c;进程和线程最大的区别就在于&#xff1a;进程是资源分配的最小单位&#xff0c;线程是cpu调度的最小单位。对于多进程开发来说&#xff0c;每一个进程都占据一块独立的虚拟内存空间&#…

Mobile net V系列详解 理论+实战(2)

Mobilenet 系列 实践部分一、数据集介绍二、模型整体框架三、模型代码详解四、总结 实践部分 本章针对实践通过使用pytorch一个实例对这部分内容进行吸收分析。本章节采用的源代码在这里感兴趣的读者可以自行下载操作。 一、数据集介绍 可以看到数据集本身被存放在了三个文件…

django学习入门系列之第十点《A 案例: 员工管理系统10》

文章目录 12 管理员操作12.4 密码加密12.5 获取对象&#xff08;防止id错误--编辑界面等&#xff09;12.6 编辑管理员12.7 重置密码 往期回顾 12 管理员操作 12.4 密码加密 密码不应该以明文的方式直接存储到数据库&#xff0c;应该加密才放进去 定义一个md5的方法&#xff…

4 html5 web components原生组件详细教程

web components 前面我们已经介绍过&#xff0c;这一期我们就来讲一讲具体用法和这其中的关键只是点&#xff1a; 1 基本使用 如果我们想实现一个封装的原生组件&#xff0c;那就离不开使用js去封装&#xff0c;这里主要就是基于HTMLElement这个类&#xff0c;去创建创建一个…

OpenCV运动分析和目标跟踪(2)累积操作函数accumulateSquare()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将源图像的平方加到累积器图像中。 该函数将输入图像 src 或其选定区域提升到2的幂次方&#xff0c;然后加到累积器 dst 中&#xff1a; dst ( …

Android WebView H5 Hybrid 混和开发

对于故乡&#xff0c;我忽然有了新的理解&#xff1a;人的故乡&#xff0c;并不止于一块特定的土地&#xff0c;而是一种辽阔无比的心情&#xff0c;不受空间和时间的限制&#xff1b;这心情一经唤起&#xff0c;就是你已经回到了故乡。——《记忆与印象》 前言 移动互联网发展…

用Python画一个五星红旗

#codingutf-8 import turtle import mathdef draw_polygon(aTurtle, size50, n3): 绘制正多边形args:aTurtle: turtle对象实例size: int类型&#xff0c;正多边形的边长n: int类型&#xff0c;是几边形 for i in range(n):aTurtle.forward(size)aTurtle.left(360.0/n)de…

esp32-C2 对接火山引擎实现语音转文本(二)

目录 一、 语音转文本初始化 二、 WedStream 事件处理函数 一、 语音转文本初始化 Volcengine_vtt_handle_t Volcengine_Vtt_Init(Volcengine_vtt_config_t *config) {// 管道配置audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();Volcengine_vtt_t *vt…

【从计算机的发展角度理解编程语言】C、CPP、Java、Python,是偶然还是应时代的产物?

参考目录 前言什么是"computer"?计算机的大致发展历程计算机系统结构阶段(1946~1981)计算机网络和视窗阶段(1982~2007)复杂信息系统阶段(2008~today)人工智能阶段 越新的语言是越好的吗、越值得学习吗&#xff1f; 前言 最近读了 《Python语言程序设计基础》 这本书…

数据结构与算法学习day21-回溯法

一、组合 1.题目 . - 力扣&#xff08;LeetCode&#xff09; 2思路 把组合问题抽象成树形结构&#xff08;N叉树&#xff09; 每次从集合中选取元素&#xff0c;可选择的范围随着选择的进行而收缩&#xff0c;调整可选择的范围。 图中可以发现n相当于树的宽度&#xff0c…

[Linux]进程控制详解

1.创建进程 进程调用fork,当控制转移到内核中的fork代码后&#xff0c;内核做&#xff1a; ● 分配新的内存块和内核数据结构给子进程 ● 将父进程部分数据结构内容拷贝至子进程 ● 添加子进程到系统进程列表当中 ● fork返回&#xff0c;开始调度器调度 这个前面提到过&#…