java中二叉树_Java工程师面试1000题224-递归非递归实现二叉树前、中、后序遍历...
224、使用递归和非递归实现二叉树的前、中、后序遍历
使用递归来实现二叉树的前、中、后序遍历比较简单,直接给出代码,我们重点讨论非递归的实现。
class Node { public int value; public Node left; public Node right; public Node() { } public Node(int value) { this.value = value; }}public class Solution { //递归实现前序遍历 public void preOrderRecur(Node head){ if (head == null) return; System.out.println(head.value + " "); preOrderRecur(head.left); preOrderRecur(head.right); } //递归实现中序遍历 public void inOrderRecur(Node head){ if (head == null) return; inOrderRecur(head.left); System.out.println(head.value + " "); inOrderRecur(head.right); } //递归实现后续遍历 public void posOrderRecur(Node head){ if (head == null) return; posOrderRecur(head.left); posOrderRecur(head.right); System.out.println(head.value + " "); }}
凡是可以使用递归可以解决的问题都可以使用非递归的方法来实现。这是因为递归方法无非就是利用函数栈来保存信息,如果用自己申请的数据结构来代替函数栈,也可以实现相同的功能。
用非递归的方法实现二叉树的先序遍历,具体过程如下:
1、申请一个新的栈,记为stack。然后将头结点head压入stack中;
2、从stack中弹出栈顶节点,记为cur,然后打印cur节点的值,再将节点cur的右孩子节点(如果不为空)先压入到stack中,最后将cur的左孩子节点(如果不为空)压入stack中。
3、不断重复步骤2,直到stack为空,过程全部结束。
下面举例说明整个过程,假如存在一颗二叉树如图所示:
- 节点1先入栈,然后弹出并打印。接下来把节点3压入栈,再把节点2压入栈,此时stack从顶到底依次为2、3;
- 节点2弹出并打印,把节点5压入栈,再把节点4压入栈,此时栈中从顶到底元素依次为4、5、3;
- 节点4弹出并打印,由于节点4没有孩子节点可以压入栈,所以此时栈中元素从顶到底依次为5、3;
- 节点5弹出并打印,由于节点5没有孩子节点可以压入栈,所以此时栈中元素仅有3;
- 节点3弹出并打印,先把节点7压入栈,再把节点6压入栈,此时栈中元素从顶到底依次为6、7;
- 节点6弹出并打印,由于节点6没有孩子节点可以压入栈,所以此时栈中元素仅有7;
- 节点7弹出并打印,由于节点7没有孩子节点可以压入栈,此时stack中为空,过程停止。
整个过程请参考如下代码:
//不用递归实现前序遍历 public void preOrderUnRecur(Node head){ System.out.print("前序遍历:"); if (head != null){ Stack stack = new Stack<>(); stack.add(head); while (!stack.isEmpty()){ head = stack.pop(); System.out.print(head.value + " "); if (head.right != null){ stack.push(head.right); } if (head.left != null){ stack.push(head.left); } } } System.out.println(); }
用非递归的方式来实现二叉树的中序遍历,具体过程如下:
- 申请一个新的栈,记为stack。初始时,令变量cur = head;
- 先把cur节点压入栈中,对以cur节点为头结点的整颗子树来说,依次把左边界压入栈中,即不停的令cur= cur.left;然后重复此步骤;
- 不断重复步骤2,直到发现cur为空,此时从stack中弹出一个节点,记为node。打印node的值,并且让cur = node.right,然后继续重复步骤2;
- 当stack为空且cur为空时,整个过程停止。
还是以上图的二叉树为例子来说明整个过程:
- 初始时cur为节点1,将节点1压入栈,令cur= cur.left,此时cur变为节点2;
- cur为节点2,将节点2压入栈中,令cur = cur.left,即此时cur变为节点4;
- cur为节点4,将节点4压入栈中,令cur = cur.left,此时cur变为了null,此时栈中元素从顶到底依次为4、2、1;
- cur为null,从栈中弹出节点4(node)并打印,并令cur = node.right,cur仍然为null,此时stack中从顶到底依次为2、1;
- cur为null,从栈中弹出节点2(node)并打印,并令cur = node.right,此时cur变为节点5,此时栈中元素只有1;
- cur为节点5,将节点5压入stack中,并令cur = cur.left,此时cur变为null,栈中元素有5、1;
- cur为null,从栈中弹出节点5(node)并打印,并令cur = node.right,即cur仍为null,此时栈中元素为1;
- cur为null,从栈中弹出节点1(node)并打印,并令cur = node.right,即cur变为节点3,此时栈中为空;
- cur为节点3,将节点3压入栈中,令cur = cur.left,此时cur变为节点6,此时栈中仅有元素3;
- cur为节点6,将节点6压入栈中,令cur = cur.left,此时cur变为null,此时栈中有元素6、3;
- cur为null,弹出节点6(node)并打印,令cur = node.right,cur仍为null,此时栈中元素仅有3;
- cur为null,弹出节点3(node)并打印,令cur = node.right,cur变为节点7,此时栈中为空;
- cur为节点7,将节点7压入栈,令cur = cur.left,此时cur变为null,此时栈中仅有元素7;
- cur为null,弹出节点7(node)并打印,令cur = node.right,cur仍然为null,此时栈stack也为null。
- cur和stack同时为null,整个过程终止。
代码如下:
//不用递归实现中序遍历 public void inOrderUnrecur(Node head){ System.out.println("in-Order:"); if (head != null){ Stack stack = new Stack<>(); while (!stack.isEmpty() || head != null){ if (head != null){ stack.push(head); head = head.left; }else { head = stack.pop(); System.out.print(head.value + " "); head = head.right; } } } System.out.println(); }
用非递归方式实现二叉树后序遍历有点麻烦。下面介绍使用两个栈来实现后序遍历的过程,具体步骤如下:
- 申请一个栈记为s1,然后将头结点压入s1中;
- 从s1中弹出的节点记为cur,然后依次将cur的左孩子和右孩子压入s1中;
- 在整个过程中,每一个从s1中弹出的节点都放进s2中;
- 不断重复步骤2和步骤3,直到s1为空,过程停止;
- 然后从s2中依次弹出节点并打印,打印的顺序就是后序遍历的顺序。
下面还是使用上面的图示二叉树来演示整个过程:
- 申请两个栈s1和s2,将头结点1压入s1中,然后再从s1中弹出节点1,再把节点1压入s2中,再把节点2和节点3一次压入s1,此时s1从栈顶到栈底元素为3、2;s2从栈顶到栈底只有1;
- 从s1中弹出节点3,节点3放入s2中,然后将节点3的两个孩子节点6和节点7一次压入s1,此时s1从栈顶到栈底元素依次为7、6、2;s2中为3、1;
- 从s1中弹出节点7,节点7放入s2中,由于节点7没有孩子,不需要往s1中添加任何元素,此时s1中保存6、2;s2中保存7、3、1;
- 从s1中弹出节点6,节点6放入s2中,由于节点6没有孩子,不需要往s1中添加任何元素,此时s1中保存2,s2中保存6、7、3、1;
- 从s1中弹出节点2,节点2放入s2中,然后将节点2的两个孩子节点4和节点5一次压入s1中,此时s1从栈顶到栈底元素为5、4;s2中存放的元素为2、6、7、3、1;
- 从s1中弹出节点5,节点5放入s2中,节点5无孩子节点,不需要往s1中添加任何元素,此时s1中保存4;s2中保存5、2、6、7、3、1;
- 从s1中弹出节点4,节点4放入s2中,节点4无孩子节点,不需要往s1中添加任何节点,此时s1中为空,s2中保存的元素从栈顶到栈底依次是4、5、2、6、7、3、1;
- 过程结束,依次弹出并打印s2中的节点即可。
通过如上过程我们知道,每棵子树的头结点都是先从s1中弹出,然后再把该节点的两个孩子节点按照先左再右的顺序依次压入s1,那么从s1弹出的顺序就是先右后左,所以从s1中弹出的顺序就是中、右、左。然后,s2重新收集的过程就是把s1的弹出顺序逆序,所以s2从栈顶到栈底的顺序就变成了左、右、中。
代码如下:
//不用递归实现后续遍历 public void posOrderUnRecur(Node head){ System.out.println("pos-order: "); if (head != null){ Stack s1 = new Stack<>(); Stack 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(); }
java中二叉树_Java工程师面试1000题224-递归非递归实现二叉树前、中、后序遍历...相关推荐
- 二叉树前中后序遍历+刷题【中】【数据结构/初阶/C语言实现】
文章目录 1. 二叉树基础操作 1.1 二叉树遍历 1.1.1 前序遍历 前序遍历(Pre-Order Traversal) 1.1.2 中序遍历 中序遍历(In-Order Traversal) 1 ...
- 二叉树的前,中,后序遍历(思路分析) [Java][数据结构]
二叉树的前,中,后序遍历(思路分析) 前序遍历: 先输出父节点, 再遍历左子树和右子树 中序遍历: 先遍历左子树, 再输出父节点,再遍历右子树 后序遍历: 先遍历左子树,再遍历右子树,最后输出父节点 ...
- Java二叉树的前中后序遍历
Java二叉树的前中后序遍历 1.前序遍历 1.1前序遍历概念 1.2前序遍历习题 2.中序遍历 2.1中序遍历概念 2.2中序遍历习题 3.后续遍历 3.1后序遍历概念 3.2后序遍历习题 大家好, ...
- 数据结构与算法(java):树-二叉树(二叉查找树(BST)、线索化二叉树、哈夫曼树、平衡二叉树【AVL】、二叉树的前中后序遍历)
二叉树 1.定义 二叉树 就是度不超过2的树(每个结点最多只有两个子结点).如图 2.特殊二叉树 满二叉树 当二叉树的每一个层的结点树都达到最大值,则这个二叉树就是满二叉树. 完全二叉树 叶结点只能出 ...
- java二叉树合并_Java(树的前中后序遍历构造二叉树题型整合)前序和中序、中序和后序、前序和后序遍历序列构造二叉树算法整合归纳...
前言 二叉树各种花里胡哨的算法题真的把我搞晕了,今天特地整理出一类有关二叉树的算法题,希望能帮助阅读到此文章的人,今后不再受此类题型的困扰. 一.题目类型 已知二叉树的两种遍历序列,请根据该序列构建二 ...
- Java~二叉树的前中后序遍历的几种方式(递归法,迭代法,标记法等)
目录 一.结点的定义 二.递归法遍历二叉树 前序遍历 中序遍历 后序遍历 三.迭代(非递归)遍历二叉树 (1).迭代模拟法 前序遍历 中序遍历 后序遍历 (2).空指针标记法 前序遍历 中序遍历 后序 ...
- spring 事务隔离级别和传播行为_Java工程师面试1000题146-Spring数据库事务传播属性和隔离级别...
146.简介一下Spring支持的数据库事务传播属性和隔离级别 介绍Spring所支持的事务和传播属性之前,我们先了解一下SpringBean的作用域,与此题无关,仅做一下简单记录. 在Spring中 ...
- java非递归遍历file树_Java语言实现非递归实现树的前中后序遍历总结
前言 三种遍历的递归写法都很好写,所以总结一下非递归写法. 先贴一张图复习一下三种遍历方式就进入正文啦~ [注:本文所有代码实现中树的结点定义如下: public class Node { int v ...
- [Leedcode][JAVA][第94/144/145题][前中后序遍历][递归][迭代][二叉树]
[问题描述][] 前序遍历 先输出当前结点的数据,再依次遍历输出左结点和右结点 中序遍历 先遍历输出左结点,再输出当前结点的数据,再遍历输出右结点 后续遍历 先遍历输出左结点,再遍历输出右结点,最后输 ...
最新文章
- 移动UI设计中的7种主要导航模式
- LSMW批处理使用方法(06)_步骤4、5
- listview刷新_Flutter NestedScrollView 滑动折叠头部下拉刷新效果
- 我就拜你为师的飞秋爱好者
- Django实现发邮件
- Android Studio 导入OpenCV 并调试运行face-detection例子
- 拓端tecdat|R语言用WinBUGS 软件对学术能力测验(SAT)建立层次(分层)贝叶斯模型
- 我要看的学习网站——php
- C语言小游戏——贪吃蛇
- 易简约个人产品中心网站源码html模板
- 计算机启动过程:MBR和BIOS
- 知识图谱从入门到应用——知识图谱的获取与构建:知识工程与知识获取
- kindle亚马逊个人文档不显示_Kindle 没东西看?一个插件就搞定!
- facenet 搭建人脸识别库
- Autoware1.14-摄像头目标检测YOLO-V3
- CRMEB小程序商城源码安装后,个人中心推广海报不显示处理方法!
- electron 打包后启动应用报错:Error: ENOENT: no such file or directory, open ‘xxx/manifest.json‘‘
- 词霸的每日一句的api接口
- 量化感知训练_《量化健身 动作精讲》:专业解读健身动作的秘密
- Xanadu:逐梦一个关于光量子计算的“新上都计划”
热门文章
- idea 调试 js
- python tkinter实例_Python tkinter模版代码实例
- 提示账户不被允许使用docker的情况
- eclipse报错找不到tools.jar
- Android开发笔记(一百零五)社会化分享SDK
- Android开发笔记(七十七)图片缓存算法
- 2db多少功率_话筒的灵敏度:-58dB+(-)2dB表示什么意思,数字大的好,还是小的好呢?...
- 根据条件返回相应值 decode(条件,值1,翻译值1,值2,翻译值2,...值n,翻译值n,缺省值)...
- jsp内置对象作业3-application用户注册
- zlib源码导读[转]