二叉树的前序遍历

递归

class TreeNode{TreeNode  left;TreeNode  right;int val;public TreeNode(){}public TreeNode(int val){ this.val = val;}public TreeNode(int val,TreeNode left,TreeNode right){this.left = left;this.right = right;this.val = val;}
}
public List<Integer> preorderTraversal(TreeNode root){List<Integer>list = new ArrayList<>();recure(root,res);return res;
}
public void recure(TreeNode root,List<Integer> res){if(root==null){return;}res.add(root.val);recure(root.left.res);recure(root.right,res);
}

迭代(栈)

本质是用栈模拟递归。每次先把该节点压入栈,把该节点的值放入集合,再把该节点的左节点压入栈。当前节点若无左节点,则从栈中弹出,再把右节点压入栈。

public List<Integer> preorderTraversal(TreeNode root){List<Integer> res = new ArrayList<>();Stack<TreeNode> stack = new Stack<>();while(root!=null || !stack.isEmpty()){if(root!=null){res.add(root.val);stack.add(root);root = root.left;}else{TreeNode x = stack.pop();root = x.right;    }}return res;}

morris 莫里斯算法(重点)

morris算法是二叉树遍历算法的进阶,该算法的空间复杂度为O(1),时间复杂度为O(n)。利用了叶子节点的空闲指针,实现空间开销的极限缩减。

morris遍历实质:对于没有左子树的结点只到达一次,对于有左子树的结点会到达两次

该树的morris遍历顺序为:1,2,4,2,5,1,3,6,3,7
1、cur先到达1节点,1有左子树,找到左子树上最右节点5,就是前驱结点pre,pre.right=1,cur左移
2、cur到达2,2有左子树,找到左子树的最右节点4,pre=4,pre.right = 2,cur左移
3、cur来到4,4没有左子树,则cur右移回到了2(cur第二次访问2),
4、cur来到2,继续找2的左子树的最右节点4,(pre为4),发现4的右指针已经指向了自己,那么就让4的右指针指向null,cur右移来到5
5、5没有左子树,则cur右移到了1
6、cur来到1,继续找1的左子树的最右节点5,发现5的右指针指向了1自己,那么就让5的右指针指向null,cur右移到3
7、cur移到3,找3的pre为6,6的右子树为null,让6的右指针指向3,cur左移到6
8、cur指向6,6没有左子树,则cur右移指向3
9、cur来到3,找3的pre为6,发现6的右指针指向3,则让pre.right=null,cur右移来到7
10、7没有左子树,cur右移指向null。遍历结束

-------------------------------------------------------------------------------------------------------------

先序: 对于第一次到达的节点直接打印,第二次到达的节点不打印就是先序遍历

对于上面morris遍历顺序,得到的结果为1,2,4,5,3,6,7

中序:对于只能来到自己一次的节点,直接打印,能来到自己两次的节点,第二次直接打印

对于上面morris遍历顺序,得到的结果为4,2,5,1,6,3,7

算法流程为:(当前节点为cur,前驱结点为pre)

  1. 若cur节点无左子节点,则cur右移,即cur = cur.right
  2. 若cur节点有左子节点,找到左子树的最右节点pre,有两种情况:
    (1) 若pre无右子节点,则让pre的右子节点指向cur,即pre.right = cur; cur左移 cur = cur.left; (说明是第一次访问cur节点)
    (2) 若pre的右子节点为cur,则让pre.right = null,cur右移 cur = cur.right。 (说明是第二次访问cur节点,并遍历完了cur结点的左子树)
public List<Integer> preorderTraversal(TreeNode root){List<Integer> res = new ArrayList<>();TreeNode pre = null;whle(root!=null){if(root.left != null){左子树不为空 找到左子树的最右节点pre = root.left;while(pre.right!=null && pre.right!=root){pre = pre.right;}if(pre.right == null){第一次访问到root节点 此时说明root节点有子节点,根据先序遍历规则根左右,此时root是根节点,点加入列表res.add(root.val);pre.right = root;root = root.left;}else{第二次访问到root节点pre.right = null;root = root.right;}}else{左子树为空 直接遍历右子树此时说明当前节点为叶子节点,加入列表res.add(root.val);root = root.right;}}return res;
}

二叉树的中序遍历

递归

public List<Integer> inorderTraversal(TreeNode root){List<Integer>list = new ArrayList<>();recure(root,res);return res;
}
public void recure(TreeNode root,List<Integer> res){if(root==null){return;}recure(root.left.res);res.add(root.val);recure(root.right,res);
}

迭代(栈)

public List<Integer> inorderTraversal(TreeNode root){List<Integer> res = new ArrayList<>();Stack<TreeNode> stack = new Stack<>();while(root!=null || !stack.isEmpty()){if(root!=null){stack.push(root);root = root.left;}else{TreeNode x = stack.pop();res.add(x.val);root = x.right;}}return res;}

morris算法

public List<Integer> inorderTraversal(TreeNode root){List<Integer> res = new ArrayList<>();TreeNode pre = null;while(root!=null){if(root.left != null){左子树不为空,找左子树的最右节点作为前驱结点prepre = root.left;while(pre.right!=null && pre.right!=root){pre = pre.right;}if(pre.right == null){左子树的最右节点的右子节点为空 让右子节点指向当前节点说明是第一次访问该root节点pre.right = root;root = root.left;}else{pre的右子节点为root 则是第二次访问root节点把root节点加入列表res.add(root.val);pre.right = null;root = root.right;}}else{root无左子节点 第一次循环必定是该节点先加入列表 即 最左边的节点res.add(root.val);如果是叶子节点 这个right必定为root节点 即该次的root是第二次指向rootroot = root.right;}}return res;}

二叉树的遍历(递归、栈、morris莫里斯算法)三种方法相关推荐

  1. 算法--三种方法求连续子数组的最大和

    这是一道考的烂的不能再烂的题目,但是依然有很多公司乐于将这样的题目作为笔试或面试题,足见其经典. 题目描述: 输入一个整形数组,数组里有正数也有负数. 数组中连续的一个或多个整数组成一个子数组,每个子 ...

  2. 二叉树的遍历-递归与非递归 - 海子

    二叉树的遍历-递归与非递归 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就是递归定义,因此采用递归的方 ...

  3. php 快速排序函数,PHP实现快速排序算法的三种方法

    摘要:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序 ...

  4. OpenCV-图像像素遍历操作的三种方法对比(程序提速)

    作者:Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 场景需求 使用OpenCV,避免不了的就是对图像像素进行操作,遍历操作更是家常便饭,当图像数据不多时, ...

  5. 算法导论中求解时间复杂度的三种方法

    这一章讲的是递归式(recurrence),递归式是一组等式或不等式,它所描述的函数是用在更小的输入下该函数的值来定义的. 本章讲了三种方法来解递归式,分别是代换法,递归树方法,主方法. 1.代换法( ...

  6. js实现阶乘算法的三种方法

    js实现阶乘算法的三种方法 // 非递归写法 function f(n) {if (0 === n) {return 1;}let res = 1;for (let i = 1; i <= n; ...

  7. 三种方法求递归算法的时间复杂度(递推,master定理,递归树)

    三种方法: 递推方法求递归算法的时间复杂性 Master定理方法求递归算法时间复杂性 递归树求解递归方程 1.递推方法求递归算法的时间复杂度 我们先来看一个经典的案例,汉诺塔问题 汉诺塔(Hanoi ...

  8. 平摊分析的三种方法(聚集、会计和势能)+举例(栈操作、二进制加法器、动态表)

    平摊分析(摊还分析) 我们有时候会有一个算法,或者只是单纯的一系列操作,当我们需要将这一些操作计算一个平均代价,但是又不涉及概率的问题,我们就可以使用平摊分析. 就比如一个月的账单,可能每一天都是正常 ...

  9. php遍历数组哪个效率高,PHP遍历数组的三种方法及效率对比分析

    PHP遍历数组的三种方法及效率对比分析 发布于 2015-03-04 21:55:27 | 129 次阅读 | 评论: 0 | 来源: 网友投递 PHP开源脚本语言PHP(外文名: Hypertext ...

最新文章

  1. java中的匿名内部类
  2. 得到 ip/掩码 的起始结束地址
  3. php 通过相对或得绝对,相对路径与绝对路径的了解与深入
  4. Python攻克之路-网络编程(文件上传实现思路)
  5. 原始dao和Mapper动态代理的开放方式---Mybatis学习笔记(六)
  6. html5 nodejs桌面开发工具,html5fromImages-nodejs生成器入门
  7. sqlserver 数据库排它锁_MySQL-锁
  8. 清华大学操作系统OS学习(一)——OS相关信息
  9. STM32之红外接收
  10. godot读写本地文件
  11. echart渲染深圳地图
  12. python123测验答案第七周_测验7: 文件和数据格式化 (第7周)
  13. 秃鹫入门4,GDB调试与OpenCV图像库
  14. css中图片缩小代码,css让图片等比例缩小的代码
  15. 【玩转微信公众平台之九】 第一个功能:消息自动回复
  16. 墙裂推荐7款办公必备软件,免费、小巧、好用
  17. python量化交易系统_Python学员作品-股票量化交易系统
  18. html需要编译执行吗,Javascript代码需要编译以后才能执行。
  19. 一文读懂 IEEE754 浮点数的表示方法
  20. windows下开发PHP扩展(无需Cygwin)

热门文章

  1. 如何操作 Office Open XML 格式文档
  2. 小米4 第三方re奇兔_再战三年?小米6支持升级Android 11,米10都没它快!
  3. scrollViewDidEndDragging和scrollViewDidEndDecelerating有什么区别呢
  4. python检测ipa证书过期时间
  5. 深入理解卷积网络的卷积
  6. 惯性室内导航入门到精通(3)-计步算法
  7. Android计步模块优化(今日步数)
  8. 计算机二级考试office资料,2017年国家计算机二级office考试资料
  9. HC-SR501人体红外感应模块程序
  10. ASF网站自带python脚本完成sentinel-1数据自动下载