二叉树的遍历


目录

  1. 递归遍历
  2. 非递归遍历
  3. Morris遍历

1. 递归遍历

递归版遍历只要当前节点不为null,就可以三次回到当前节点。

public static void preOrderRecur(Node head) {if (head == null) {return;}System.out.print(head.value + " ");preOrderRecur(head.left);preOrderRecur(head.right);}public static void inOrderRecur(Node head) {if (head == null) {return;}inOrderRecur(head.left);System.out.print(head.value + " ");inOrderRecur(head.right);}public static void posOrderRecur(Node head) {if (head == null) {return;}posOrderRecur(head.left);posOrderRecur(head.right);System.out.print(head.value + " ");}

2. 非递归遍历

其中后序遍历打印顺序为左右中,由先序遍历打印顺序为中左右,所以可以对先序遍历改进为中右左(改变添加顺序),添加到另外一个栈中,最后遍历打印就是左右中顺序了。

public static void preOrderUnRecur(Node head) {System.out.println("pre-order: ");while (head != null) {Stack<Node> stack = new Stack<>();stack.push(head);while (!stack.isEmpty()) {Node node = stack.pop();System.out.println(node.value + " ");if (node.right != null) {stack.push(node.right);}if (node.left != null) {stack.push(node.left);}}}}public static void inOrderUnRecur(Node head) {System.out.print("in-order: ");if (head != null) {Stack<Node> stack = new Stack<>();while (!stack.isEmpty() || head != null) {if (head != null) {stack.push(head.left);head = head.left;} else {head = stack.pop();System.out.println(head.value + " ");head = head.right;}}}System.out.println();}public static void posOrderUnRecur1(Node head) {System.out.print("pos-order: ");if (head != null) {Stack<Node> s1 = new Stack<>();Stack<Node> s2 = new Stack<>();s1.push(head);while (!s1.isEmpty()) {head = s1.pop();s2.push(head);if (head.left != null) {s1.push(head.left);}if (head.right != null) {s1.push(head.right);}while (!s2.isEmpty()) {System.out.print(s2.pop().value + " ");}}}System.out.println();}

3. Morris遍历

Morris遍历法,能以时间复杂度O(N),空间复杂度O(1)实现二叉树的遍历。

程序流程:
假设指针cur指向当前节点,cur从头结点开始。

  1. 如果cur无左孩子,则cur = cur.right;
  2. 如果cur有左孩子,则找到cur左子树上最右的节点,记为mostRight,分为以下两种情况:
    1. 若mostRight的right指针为null,则让其指向cur,且cur = cur.left;
    2. 若mostRight的right指针指向cur,则让其指回null,且cur = cur.right。

假设二叉树如下:

           12        34    5   6    7

则Morris遍历顺序为:1,2,4,2,5,1,3,6,3,7

Morris 遍历代码实现:

public static void morrisIn(Node head) {if (head == null) {return;}Node cur = head;Node mostRight = null;while (cur != null) {mostRight = cur.left;if (mostRight != null) {while (mostRight.right != null && mostRight.right != cur) {mostRight = mostRight.right;}if (mostRight.right == null) {mostRight.right = cur;cur = cur.left;continue;} else {mostRight.right = null;}}cur = cur.right;}}

特点:

  1. 当某个节点有左子树,则会到达该节点两次,如果没有左子树,只会到达一次。
  2. 当第二次回到某个节点时,它的左子树已遍历完。

实质:
Morris遍历是利用左子树最右节点的指针指向null或指向自己来标记是第一次来到该节点还是第二次来到该节点。


Morris遍历改先序遍历

在以下两种情况下打印节点:

  1. 当节点没有左子树时,打印当前节点;
  2. 当节点有左子树时并且第一次访问时打印该节点,就是当mosrRight的右指针为null时。
public static void morrisPre(Node head) {if (head == null) {return;}Node cur = head;Node mostRight = null;while (cur != null) {mostRight = cur.left;if (mostRight != null) {while (mostRight.right != null && mostRight.right != cur) {mostRight = mostRight.right;}if (mostRight.right == null) {mostRight.right = cur;System.out.print(cur.value + " ");cur = cur.left;continue;} else {mostRight.right = null;}} else {System.out.print(cur.value + " ");}cur = cur.right;}System.out.println();}

Morris遍历改中序遍历

在以下两种情况下打印节点:

  1. 当节点没有左子树时,说明第一次和第二次是重合在一起的,打印当前节点即可。
  2. 当节点有左子树时,那么需要处理完左子树再打印,即当前节点准备右移时打印。
public static void morrisIn(Node head) {if (head == null) {return;}Node cur = head;Node mostRight = null;while (cur != null) {mostRight = cur.left;if (mostRight != null) {while (mostRight.right != null && mostRight.right != cur) {mostRight = mostRight.right;}if (mostRight.right == null) {mostRight.right = cur;cur = cur.left;continue;} else {mostRight.right = null;}}System.out.print(cur.value + " ");cur = cur.right;}System.out.println();}

Morris遍历改后序遍历

在以下两种情况下打印节点:

  1. 只有当到达某个节点两次时逆序打印该节点左子树的右边界;
  2. 在代码的最后逆序打印整棵树的右边界,而逆序的过程就和单向链表的反转过程类似。
public static void morrisPos(Node head) {if (head == null) {return;}Node cur1 = head;Node cur2 = null;while (cur1 != null) {cur2 = cur1.left;if (cur2 != null) {while (cur2.right != null && cur2.right != cur1) {cur2 = cur2.right;}if (cur2.right == null) {cur2.right = cur1;cur1 = cur1.left;continue;} else {cur2.right = null;printEdge(cur1.left);}}cur1 = cur1.right;}printEdge(head);System.out.println();}public static void printEdge(Node head) {Node tail = reverseEdge(head);Node cur = tail;while (cur != null) {System.out.print(cur.value + " ");cur = cur.right;}reverseEdge(tail);}public static Node reverseEdge(Node from) {Node pre = null;Node next = null;while (from != null) {next = from.right;from.right = pre;pre = from;from = next;}return pre;}

二叉树的遍历(递归,非递归,Morris)相关推荐

  1. 二叉树的遍历(非递归)整理

    二叉树的遍历(非递归) 写在前面 二叉树重要,重要,重要.以下代码每日手撸一遍,深刻理解. 二叉树的先序遍历(非递归) 巧记心法 判断是否为空树 1.右侧入栈(访问,q指向右孩子,不空则入栈) 2.p ...

  2. 二叉树深度优先遍历(非递归)

    二叉树深度优先遍历(非递归) 1. 先序遍历非递归化 从根结点开始入栈一个元素 不停的执行以下操作: 如果栈不空,就出栈一个元素,并对其进行访问,并访问其左右孩子 若左右孩子存在,则依次入栈,右孩子先 ...

  3. 二叉树(2)——遍历的非递归实现

    2019独角兽企业重金招聘Python工程师标准>>> 算法概述 递归算法简洁明了.可读性好,但与非递归算法相比要消耗更多的时间和存储空间.为提高效率,我们可采用一种非递归的二叉树遍 ...

  4. 二叉树的遍历(非递归)

    由于二叉树的递归方法实际上是系统在使用栈进行操作,因此我们的迭代(非递归)方法也就需要使用栈进行模拟. 一.先序遍历 我们需要明白,进栈的元素都是树的根节点 root. 所以我们需要先访问该节点,再将 ...

  5. 二叉树的遍历(非递归方式)

    前序非递归遍历(借用栈结构): ①将根节点入栈: ②判栈空,获取栈顶元素输出: ③判断右子树是否为空,再判断左子树是否为空,在回至②执行. void PreOrder(BinTree bt) {sta ...

  6. php二叉树基本遍历和非递归遍历

    tree.php <?php require_once "./zhan.php"; class BinNode{public $ch;public $lchild;publi ...

  7. 一文彻底搞定二叉树的前序、中序、后序遍历(图解递归非递归)

    前言 大家好,我是bigsai,在数据结构与算法中,二叉树无论是考研.笔试都是非常高频的考点内容,在二叉树中,二叉树的遍历又是非常重要的知识点,今天给大家讲讲二叉树的层序遍历. 这部分很多人可能会但是 ...

  8. 二叉树遍历详解(递归遍历、非递归栈遍历,Morris遍历)

    一.前言 <二叉查找树全面详细介绍>中讲解了二叉树操作:搜索(查找).遍历.插入.删除.其中遍历深度优先遍历(DFS)按照实现方法可以分为:递归遍历实现.非递归遍历实现.Morris遍历实 ...

  9. java 建树源码_Java实现的二叉树常用操作【前序建树,前中后递归非递归遍历及层序遍历】...

    import java.util.ArrayDeque; import java.util.Queue; import java.util.Stack; //二叉树的建树,前中后 递归非递归遍历 层序 ...

  10. 漫谈二叉树遍历(非递归)

    ------这篇文章旨在提出一种简单方便,易于理解时空复杂度低且风格统一的二叉树非递归遍历方法. 从二叉树先序遍历开始 二叉树的先序遍历(非递归)相比中后序是最少花哨.最统一的.一般来说先序遍历的代码 ...

最新文章

  1. 获取序列全排列Java,java中全排列的生成算法汇总
  2. Python 3.5将支持Async/Await异步编程
  3. Python函数的装饰器,两层装饰器和三层装饰器
  4. SVN中忘记上传自己写的工程,但是IP已经变了的解决方案
  5. 程序员过关斩将--cookie和session的关系其实很简单
  6. 字符串substring方法在jkd6,7,8中的差异
  7. 关系数据库——mysql常用函数总结
  8. 人之间的尊重是相互的_人与人之间的感情,最基本的是相互尊重
  9. 2021年qs世界大学计算机科学排名,2015年QS世界大学计算机专业排名
  10. c++11 lambda(匿名函数)
  11. Java 8 中的 java.util.Optional
  12. JDK8帮助文档生成-笔记
  13. 晶科鑫 | 国产26MHz晶振匹配Espressif(乐鑫) ESP8285/ESP8266芯片案例
  14. 数值计算笔记之数值计算中应注意的问题
  15. PS完美抠取头发丝----更换证件照背景完美去白边/蓝边/红边-----超实用方法
  16. Transit VPC Transit Gateway
  17. java1.8新特性之stream流式算法
  18. 前端拖拽时手型为禁用
  19. JDT操作AST重构if块
  20. 光遇服务器维护要多久,光遇:你玩游戏多久了?半年以上的老玩家,是如何坚持下去的?...

热门文章

  1. Python2 之 print函数示例
  2. 2016网络安全***赛记录
  3. 柯南君:看大数据时代下的IT架构(4)消息队列之RabbitMQ--案例(Helloword起航)...
  4. paper reference
  5. 剑指-从尾到头打印链表
  6. UVA307 Sticks小木棍
  7. TensorFlow2-自编码器
  8. EOJ_1007_环形双向链表
  9. httpclient 设置超时时间_面试官:技术选型,HttpClient还是OkHttp?
  10. 集线器(Hub)、交换机(Switch)与路由器(Router)之间的区别和联系