一天一大 lee(二叉树的中序遍历)难度:中等-Day20200914
时间:2022-07-25
本文章向大家介绍一天一大 lee(二叉树的中序遍历)难度:中等-Day20200914,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目:
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
抛砖引玉
抛砖引玉
思路
二叉树的中序遍历:
左子树——>根节点——>右子树
**注意:**这个遍历顺序不仅仅是遍历二叉树整体的顺序也是遍历所有子树的顺序
递归
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var inorderTraversal = function(root) {
let _result = []
function helper(node) {
if (!node) {
return
}
// 先深层遍历左子树
helper(node.left)
// 再遍历左子树的根节点
_result.push(node.val)
// 最后深层遍历当前根节点的右子树
helper(node.right)
}
helper(root)
return _result
}
栈
递归方法采用了深度优先遍历的形式,一般可以采用深度优先遍历就可以采用广度优先遍历。
- 从根节点开始这个查找其左节点(先入后出)
- 遍历完左节点,逐个取出栈内节点
- 当前节点不仅仅是单个二叉树节点,也可能是二叉子树,如果其是二叉子树同样遍历其左节点入栈
var inorderTraversal = function(root) {
let _result = [],
stack = []
while (root || stack.length) {
// 遍历节点左子树,入栈
while (root) {
stack.push(root)
root = root.left
}
// 节点(子树)逐个出栈,存放到结果数字
root = stack.pop()
_result.push(root.val)
// 如果出栈的是子树则同第一个有节点开始重复上面的逻辑
root = root.right
}
return _result
}
Morris 中序遍历
在20200808: 恢复二叉搜索树 (难度:困难)中,还遇到了Morris 中序遍历的方法
假设当前遍历到的节点为 node:
- 如果 node 无左孩子,先将 node 的值加入答案数组,再访问 node的右孩子,即 node = node.right
- 如果 node 有左孩子,则找到 node 左子树上最右的节点(即左子树中序遍历的最后一个节点,node 在中序遍历中的前驱节点),记为predecessor。根据predecessor 的右孩子是否为空,进行如下操作:
- 如果predecessor 的右孩子为空,则将其右孩子指向 node,然后访问 node 的左孩子,即 node = node.left
- 如果predecessor 的右孩子不为空,则此时其右孩子指向 node,说明我们已经遍历完 node 的左子树,将predecessor 的右孩子置空,将 node 的值加入答案数组,然后访问 node 的右孩子,即 node = node.right
简要的讲就是,在中序遍历是在左子树走到尽头是,需要回溯到之前出现的某个节点的右节点上,就使用predecessor记录这个回溯的位置,是不存在关系的节点在遍历时连续起来。
var inorderTraversal = function(root) {
let _result = [],
predecessor = null
while (root) {
if (root.left) {
// predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
predecessor = root.left
while (predecessor.right && predecessor.right !== root) {
predecessor = predecessor.right
}
// 让 predecessor 的右指针指向 root,继续遍历左子树
if (!predecessor.right) {
predecessor.right = root
root = root.left
}
// 说明左子树已经访问完了,我们需要断开链接
else {
_result.push(root.val)
predecessor.right = null
root = root.right
}
}
// 如果没有左孩子,则直接访问右孩子
else {
_result.push(root.val)
root = root.right
}
}
return _result
}
- 地理坐标系与投影坐标系的区别
- ExtJs学习笔记(6)_可分页的GridPanel
- PowerDesinger联系的定义及使用
- Gis链接
- TortoiseSVN文件夹及文件图标不显示解决方法 TortoiseSVN文件夹及文件图标不显示解决方法
- 地图坐标
- PowerDesigner15连接Oracle失败的解决办法
- 地图校正方法心得
- 工作流参考模型点评
- 按图索骥:SQL中数据倾斜问题的处理思路与方法
- [方法“Boolean Contains(System.Guid)”不支持转换为 SQL]的解决办法
- DataBind的一些试验
- 继承HibernateDaoSupport时遇到的问题 使用注解为HibernateDaoSupport注入sessionFa
- 常用代码
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【译】算法的记录
- 运行时类型识别
- 外观模式-分析和C++实现
- CSS八种让人眼前一亮的HOVER效果
- 懒加载图片以获取最佳性能的最佳方案
- Egg.js 试水 - 天气预报
- Egg.js试水 - 文章增删改查【前后端分离】
- Flutter基础widgets教程-Offstage篇
- 一份礼物.apk - o泡果奶-的逆向分析
- 代码审计-.NET下的序列化与反序列化(BinaryFormatter)
- 02.视频播放器整体结构
- Spring中@Component和@Bean
- HTTP对接方式
- 使用ShardingSphere 过程中遇到的关于spring boot 版本的问题
- 腾讯云TKE-Pod案例: 容器内crontab问题