所有涉及到中序遍历的题都可以使用该模板解决
中序遍历(inorderTraversal)有递归,迭代,莫里斯三种解法

递归版

public List<Integer> inorderTraversal(TreeNode root) {//具体的细节可以和这里不一样,但思路一致即可,就是左子树递归->root->右子树递归List<Integer> ans = new ArrayList<>();getAns(root, ans);return ans;
}private void getAns(TreeNode node, List<Integer> ans) {if (node == null) {return;}getAns(node.left, ans); ans.add(node.val);getAns(node.right, ans);
}

时间复杂度:O(n),遍历每个节点。

空间复杂度:O(h),压栈消耗,h 是二叉树的高度。

迭代版

Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur != null || !stack.isEmpty()){while(cur != null){stack.push(cur);cur = cur.left;}cur = stack.pop();/** do something **/cur = cur.right;
}

时间复杂度:O(n)。

空间复杂度:O(h),栈消耗,h 是二叉树的高度。

Morris遍历

解法一和解法二本质上是一致的,都需要 O(h)的空间来保存上一层的信息。而我们注意到中序遍历,就是遍历完左子树,然后遍历根节点。如果我们把当前根节点存起来,然后遍历左子树,左子树遍历完以后回到当前根节点cur就可以了,怎么做到呢?
我们注意到左子树cur.left最右边的节点last的右孩子是null,我们可以将last.right = cur即保留当前根节点即可,这样我们遍历完左子树,就可以回到根节点了。
如果当前根节点的左子树为null,那我们就直接遍历根节点,再考虑右子树cur = cur.right;

所以总体思想就是:记当前遍历的节点为 cur:

  1. cur.left 为null,保存cur的值,更新cur为cur.right;
  2. cur.left不为null,记prev = cur.left,找到左子树的最右边节点记为last;
  3. 如果last.right为null,将last.right = cur;更新cur = cur.left;
  4. 如果last.right不为null,说明之前已经访问过,第二次来到这里,表明当前子树遍历完成,将last.right = null;保存cur的值,更新cur为cur.right。
    结合图示:

    如上图,cur 指向根节点。 当前属于 3 的情况,cur.left 不为 null,cur 的左子树最右边的节点的右孩子为 null,那么我们把最右边的节点的右孩子指向 cur。

    接着,更新 cur = cur.left。

    如上图,当前属于 3 的情况,cur.left 不为 null,cur 的左子树最右边的节点的右孩子为 null,那么我们把最右边的节点的右孩子指向 cur。

    更新 cur = cur.left。

    如上图,当前属于情况 1,cur.left 为 null,保存 cur 的值,更新 cur = cur.right。

    如上图,当前属于 4 的情况,cur.left 不为 null,cur 的左子树最右边的节点的右孩子已经指向 cur,保存 cur 的值,更新 cur = cur.right。

    如上图,当前属于情况 1,cur.left 为 null,保存 cur 的值,更新 cur = cur.right。

    如上图,当前属于4的情况,cur.left 不为 null,cur 的左子树最右边的节点的右孩子已经指向 cur,保存 cur 的值,更新 cur = cur.right。

    当前属于情况 1,cur.left 为 null,保存 cur 的值,更新 cur = cur.right。

    cur 指向 null,结束遍历。

根据这个关系,写代码:

public List<Integer> inorderTraversal(TreeNode root) {List<Integer> ans = new ArrayList<>();TreeNode cur = root;while(cur != null){if(cur.left == null){ans.add(cur.val);  //do somethingcur = cur.right;}else{TreeNode prev = cur.left;while(prev.right != null && prev.right != cur)prev = prev.right;//情况3    if(prev.right == null){prev.right = cur;cur = cur.left;}    //情况4,不用担心前一个if会影响后一个,因为cur已经改变了if(prev.right == cur){prev.right = null;ans.add(cur.val);  //do somethingcur = cur.right;}}}return ans;   //依据实际情况返回

时间复杂度:O(n)。每个节点遍历常数次。

空间复杂度:O(1)。

树的中序遍历(递归,迭代,莫里斯)相关推荐

  1. 二叉树的中序遍历 [递归 迭代]

    中序遍历的递归 & 迭代 前言 一.二叉树的中序遍历 二.递归 & 迭代 1.递归版 2.迭代(断左子树版) 3.迭代(root迭代版) 4.mirror(O(1)空间版) 总结 参考 ...

  2. LeetCode 94. 二叉树的中序遍历(递归)(迭代)(颜色标记法)

    题目描述 给定一个二叉树,返回它的后序遍历 思路 详见链接 代码 递归 #class TreeNode: # def __init__(self,x): # self.val = x # self.l ...

  3. 怎样将树的中序遍历的数输入到一个数组中_数据结构与算法-二叉查找树平衡(DSW)...

    上一节探讨了二叉查找树的基本操作,二叉查找树的查找效率在理想状态下是O(lgn),使用该树进行查找总是比链表快得多.但是,该论点并不总是正确,因为查找效率和二叉树的形状息息相关.就像这样: 图1-1给 ...

  4. Morris遍历算法 树的中序遍历

    Morris遍历算法 树的中序遍历 树的中序遍历 一.普通方法 1.递归实现 2.栈实现 二.Morris遍历 1.算法 2.代码 总结 树的中序遍历 对于当前结点,先输出它的左孩子,然后输出该结点, ...

  5. 为什么普通树没有中序遍历和森林没有后序遍历

    本文为个人理解,若有错误欢迎指正! 这里说的树当然是指普通的树,而不是树中比较特别的二叉树. 1.为什么普通树没有中序遍历 中序遍历是对于二叉树而言: 中序遍历左子树,访问根结点,中序遍历右结点. 在 ...

  6. 数据结构二叉树中序遍历递归和非递归算法

    2022.11.19 二叉树中序遍历递归和非递归算法 任务描述 相关知识 编程要求 测试说明 C/C++代码 任务描述 本关任务:给定一棵二叉树,使用递归和非递归的方法实现二叉树的中序遍历结果. 相关 ...

  7. LeetCode 94. Binary Tree Inorder Traversal--二叉树中序遍历--递归,迭代--C++,Python解法

    题目地址:Binary Tree Inorder Traversal - LeetCode Given a binary tree, return the inorder traversal of i ...

  8. [Leedcode][JAVA][第94/144/145题][前中后序遍历][递归][迭代][二叉树]

    [问题描述][] 前序遍历 先输出当前结点的数据,再依次遍历输出左结点和右结点 中序遍历 先遍历输出左结点,再输出当前结点的数据,再遍历输出右结点 后续遍历 先遍历输出左结点,再遍历输出右结点,最后输 ...

  9. 剑指offer面试题36. 二叉搜索树与双向链表(中序遍历)(递归)

    题目描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表.要求不能创建任何新的节点,只能调整树中节点指针的指向. 思路 详见链接 代码 #class Node: # def __ini ...

  10. 二叉树的中序遍历 递归与非递归

    94. 二叉树的中序遍历 给定一个二叉树的根节点 root ,返回它的 中序 遍历. 示例 1: 输入:root = [1,null,2,3] 输出:[1,3,2] 示例 2: 输入:root = [ ...

最新文章

  1. python个人项目-软工作业个人项目wc.exe(python实现)
  2. 技巧: 用 JAXM 发送和接收 SOAP 消息—Java API 使许多手工生成和发送消息方面必需的步骤自动化...
  3. 卸载重装svn后原来项目不受管理,版本不对应还是,升级工作副本解决?
  4. 使用jQuery实现图片懒加载原理
  5. angularjs 整合bootstrap 时间控件
  6. Pytorch基础(三)—— DataSet的应用
  7. RHEL 5服务篇—常用网络配置命令
  8. 为什么说黄桃罐头是东北的人参果
  9. ComboBox信息读取
  10. 利用AjaxPro从客户端调用服务端函数的方法
  11. Flink on Zeppelin (3) - Streaming 篇
  12. 中国人工智能学会通讯——一种基于众包的交互式数据修复方法 3 给定质量约束下的交互式算法...
  13. Word排版艺术 读后感
  14. Open Cube 时信魔方介绍
  15. 最小二乘法算法C语言,最小二乘法C算法终极整理版本,绝对原创!
  16. [电影]《指环王》新老三部曲完全赏析(王者归来)
  17. c语言实例--打渔晒网问题
  18. [前端]-- jquery学习1
  19. 移动路由器做网站服务器,移动路由器上网方式选哪个?
  20. KT148A语音芯片ic的硬件设计注意事项

热门文章

  1. Mac OS X Safari 插件存放位置
  2. 电脑仙人掌机器人作文_蜗牛、仙人掌、电脑、雪人、机器人、蚕宝宝、大象选三到四个词作文...
  3. Linux就这个范儿 第16章 谁都可以从头再来--从头开始编译一套Linux系统 nsswitch.conf配置文件...
  4. 技术可行性与操作可行性的资料搜集与分析
  5. Android adb截图后保存到电脑
  6. 华氏温度转换为摄氏温度,c语言实例一
  7. 最新matlab音乐合成实验报告,Matlab音乐合成实验报告
  8. C#读取文本框(TextBox)数据并统计其中最大小值平均值及求出所在数组中位置,在文本框中显示
  9. 深圳大学计算机系在哪个校区,2021年深圳大学有几个校区,大一新生在哪个校区...
  10. Android 利用重力感应调整手机模式