中序遍历的递归 & 迭代

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

前言

中序遍历,递归进行左中右遍历,非常简单高效。迭代的方式稍显麻烦,不过也是遵循左中右遍历的原则。而在迭代方法中,将二叉树原地修改成双向循环链表,再进行遍历,则需要栈空间,就可以完成迭代版的中序遍历。

一、二叉树的中序遍历

二、递归 & 迭代

1、递归版

 // Definition for a binary tree node.public class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) {this.val = val;}TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}}List<Integer> ans = new ArrayList<>();public List<Integer> inorderTraversal(TreeNode root) {if(null == root) return ans;inorderTraversal(root.left);ans.add(root.val);inorderTraversal(root.right);return ans;}

2、迭代(断左子树版)

// 断链法,按自己独立思考复杂的逻辑来的。// 靠peek()节点遍历。public List<Integer> inorderTraversal2(TreeNode root) {if (null == root) return ans;Stack<TreeNode> sk = new Stack<>();sk.push(root);while (!sk.isEmpty()) {// while不断left压栈。while (sk.peek().left != null) {TreeNode left = sk.peek().left;sk.peek().left = null;sk.push(left);}// 一旦不断left到底了,至少说明没有左孩子了(null孩子不加入!),直接访问当前节点。ans.add(sk.peek().val);// if将右节点当作一个子树来对待,重新进入循环进行left压栈。if (sk.peek().right != null) {TreeNode right = sk.peek().right;sk.pop().right = null;sk.push(right);} else sk.pop();}return ans;}

3、迭代(root迭代版)

// 不断链,而是更新root!// 靠root节点遍历。public List<Integer> inorderTraversal3(TreeNode root) {if (null == root) return ans;Stack<TreeNode> sk = new Stack<>();while (root != null || !sk.isEmpty()) {// 遍历左节点。while (root != null) {sk.push(root);root = root.left;}// 靠着栈轨迹,把root拉回来。root = sk.pop();// 访问根节点。ans.add(root.val);// 靠着栈轨迹的root,寻找右子树。root = root.right;}return ans;}

4、mirror(O(1)空间版)

// mirror法:将左子树最右孩子的指针指向该节点,即让前驱节点的next指向自己,形成左中右的单向链,让空间复杂度降到O(1)public List<Integer> inorderTraversal4(TreeNode root) {if (null == root) return ans;while (root != null) {// 让root的前驱指向自己,前驱在左子树的最右节点上。if (root.left != null) {TreeNode p = root.left;// p.right != root,防止重复访问左边,导致死循环。while (p.right != null && p.right != root) p = p.right;if (p.right == null) {p.right = root;// 继续遍历左子树,设置好right指针。root = root.left;}// 说明p.right == root,说明左子树已经遍历完了,访问自己 + 访问右子树。// 注:如果想要不修改树结构,即可把right断掉。else {ans.add(root.val);root = root.right;// 可把right断掉,保持原来的树结构。p.right = null;}} else {ans.add(root.val);root = root.right;}}return ans;}

总结

1)二叉树的遍历,遵循左中右原则,递归 / 迭代都可。一题多解,对问题中涵盖的知识点才能融汇贯通,比如这里对左中右遍历的理解,在迭代情况下get值的时机,对二叉树这种递归结构 的理解,对二叉树&双向链表的关系,通过mirror联想到线索二叉树等等。

2)迭代版中的mirror版,可以将空间复杂度降到O(1)。需要理解临时修改right指针,把二叉树当成双向链表看待,也可以想象一下二叉搜索树的样子,是否也是同个原理!

3)coding要实际,不能只看看,比如这里独立思考的断链法和root法还是在思想上有很大不同,虽然root法很容易理解,但不是我能输出的!比如root法中while(root != null || !sk.isEmpty())为什么要两个条件,又为什么要或运算,这都需要实际coding并加强理解!比如mirror法为什么空间O(1),修改right指针的本质?为什么每个节点会被访问两次?在mirror版下在那两种情况下访问节点?left == null时可访问,有环的情况可访问,一种是左孩子为null,一种是左孩子被访问过,不用再访问了。

4)每次访问了,就root = root.right,左子树就不用过问了,为什么这样,需要深刻理解树的递归结构,每一个节点都是root

参考文献

[1] LeetCode 二叉树的中序遍历

[2] LeetCode 二叉树的中序遍历 mirror版

二叉树的中序遍历 [递归 迭代]相关推荐

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

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

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

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

  3. 二叉树的中序遍历-递归和非递归算法

    创建二叉树就不说了,这里直接: 中序递归遍历算法 void InOrder(BiTree T){if(T){InOrder(T->lchild);cout<<T->data&l ...

  4. Leetcode题库 94.二叉树的中序遍历(递归 C实现)

    文章目录 解析 代码 解析 中序遍历:先左再中后右 Func函数,接收一个节点,节点非空,则先遍历其左子树,再存入自身val值,最后遍历右子树 ret数组存储每个非空节点的val值 pos为下一个存入 ...

  5. LeetCode 145. 二叉树的后序遍历(递归)(迭代)(颜色标记法)

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

  6. 二叉树的中序遍历(C语言)

    我们从两个方向讲解二叉树的中序遍历(递归+迭代) 一.递归 思想: 从根节点开始向其的左孩子遍历,一直访问每个节点的左孩子,当其走到NULL时返回,返回时记录每个节点的数值,然后访问该节点的右孩子,如 ...

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

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

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

    二叉树的中序非递归遍历 中序遍历的非递归算法描述如下: 从根节点开始检索,如果当前节点不为空,则将当前节点入栈,让当前节点成为其左孩子节点,再继续上一步的操作 加入当前节点为空了,说明其父节点已经没有 ...

  9. LeetCode-二叉树-94. 二叉树的中序遍历

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

最新文章

  1. jffs2 告警 和 一般性错误
  2. Android Studio开发入门-引用jar及so文件
  3. SQL实战之找出所有员工当前薪水salary情况
  4. IE6 PNG透明终极解决方案
  5. Nginx 如何开启gzip 来提高页面加载速度
  6. phpmyadmin安装配置以及相关问题
  7. css鼠标拖拉卡顿_66个值得收藏的CSS开发技巧
  8. Focal Loss for Dense Object Detection解读
  9. C语言自学笔记(16)
  10. 输出2—1000的所有同构数c语言详解
  11. MySQL 导入数据 时间数据 不准确 解决办法
  12. 分析公司盈利能力的方法
  13. java如何爬取qq音乐_爬取QQ音乐
  14. HTML5大前端开发有哪些常用工具?
  15. C#二次开发CAD常用的方法和注意事项
  16. android 电话录音功能,Android实现电话录音功能
  17. echarts5.0lengend的全选加自定义icon功能
  18. Ciso 静态路由配置
  19. oracle中取反_取反函数
  20. Translation插件谷歌翻译引擎无法使用

热门文章

  1. MyBatis关联对象查询
  2. 各纬度气候分布图_气候气压带图_世界气候气压带风带分布图要图(需要表识纬度)-4d影院专题信息栏目...
  3. PnPUtil (PnPUtil.exe) 是一个命令行工具,使管理员可以执行以下操作驱动程序包
  4. 关于:复杂是软件的死敌
  5. 重置ubuntu密码
  6. github上很好的iOS资源集锦
  7. IWDG和WWDG分析
  8. 【优化调度】基于粒子群算法求解水火电调度优化问题含Matlab源码
  9. sld样式文件demo
  10. shell中各种括号的作用详解()、(())、[]、[[]]、{}(推荐)