【Java】 二叉树的遍历(递归与循环+层序遍历)
在【Java】 大话数据结构(9) 树(二叉树、线索二叉树)一文中,已经实现了采用递归方法的前、中、后序遍历,本文补充了采用循环的实现方法、以及层序遍历并进行了一个总结。
递归实现
- /*
- * 前序遍历
- */
- public void preOrder() {
- preOrderTraverse(root);
- System.out.println();
- }
- private void preOrderTraverse(BiTNode<E> node) {
- if(node==null)
- return;
- System.out.print(node.data);
- preOrderTraverse(node.lchild);
- preOrderTraverse(node.rchild);
- }
- /*
- * 中序遍历
- */
- public void inOrder() {
- inOrderTraverse(root);
- System.out.println();
- }
- private void inOrderTraverse(BiTNode<E> node) {
- if(node==null)
- return;
- inOrderTraverse(node.lchild);
- System.out.print(node.data);
- inOrderTraverse(node.rchild);
- }
- /*
- * 后序遍历
- */
- public void postOrder() {
- postOrderTraverse(root);
- System.out.println();
- }
- private void postOrderTraverse(BiTNode<E> node) {
- if(node==null)
- return;
- postOrderTraverse(node.lchild);
- postOrderTraverse(node.rchild);
- System.out.print(node.data);
- }
非递归实现(迭代)
非递归实现,需要先创建一个栈,利用其特性来进行储存和输出。
- 前序遍历,先输出当前点的值,一直沿着左子树进行读取,没左子树就在右子树重复上述过程。
- 中序遍历与前序遍历基本一致,只是输出值的代码位置不同。
- 后序遍历由于要左右子树输出完后才能输出根结点,所以增加一个栈进行标记是否完成左右子树的输出,其余思想基本类似。
下面代码中,要注意node的结点位置和stack.peek()的位置关系。
此外,在后序非递归遍历的过程中,栈中保留的是当前结点的所有祖先。这是和先序及中序遍历不同的。在某些和祖先有关的算法中,此算法很有价值。
- /**
- * 前序遍历(非递归)
- */
- public void preOrder2() {
- preOrder2(root);
- System.out.println();
- }
- private void preOrder2(BiTNode node) {
- Stack<BiTNode> stack = new Stack<BiTNode>();
- while(node!=null||!stack.isEmpty()) {
- while(node!=null) {
- System.out.print(node.data);
- stack.push(node);
- node=node.lchild;
- }
- node=stack.pop().rchild;
- }
- }
- /**
- * 中序遍历
- */
- public void inOrder2() {
- inOrder2(root);
- System.out.println();
- }
- private void inOrder2(BiTNode node) {
- Stack<BiTNode> stack = new Stack<BiTNode>();
- while(node!=null||!stack.isEmpty()) {
- while(node!=null) {
- stack.push(node);
- node=node.lchild;
- }
- node=stack.pop();
- System.out.print(node.data);
- node=node.rchild;
- }
- }
- /**
- * 后序遍历
- */
- public void postOrder2() {
- postOrder2(root);
- System.out.println();
- }
- private void postOrder2(BiTNode node) {
- Stack<BiTNode> stack = new Stack<BiTNode>();
- Stack<Integer> tag = new Stack<Integer>();
//下面这段注释也能实现,与后面未注释部分基本一致。代表了自己的思考过程,就不删除了- // while(node!=null||!stack.isEmpty()) {
- // while(node!=null){
- // stack.push(node);
- // tag.push(0);
- // node=node.lchild;
- // }
- //注释中的tag用于标记当前结点是否完成左右子结点遍历(所以用0,1表示)
- // while(!tag.isEmpty()&&tag.peek()==1) { //栈顶节点的左右子结点已完成遍历
- // System.out.print(stack.pop().data);
- // tag.pop();
- // }
- // if(!tag.isEmpty()) { //上面和这里的 !flag.isEmpty() 不可省略,不然会出错。
- // tag.pop();
- // tag.push(1);
- // node=stack.peek().rchild;
- // }
- // }
- /*后序遍历时,分别从左子树和右子树共两次返回根结点(用tag表示次数),
- * 只有从右子树返回时才访问根结点,所以增加一个栈标记到达结点的次序。
- */
- while(node!=null||!stack.isEmpty()) {
- if(node!=null){
- stack.push(node);
- tag.push(1); //第一次访问
- node=node.lchild;
- }else {
- if(tag.peek()==2) {
- System.out.print(stack.pop().data);
- tag.pop();
- }else {
- tag.pop();
- tag.push(2); //第二次访问
- node=stack.peek().rchild;
- }
- }
- }
- }
20191104:前序和后序的非递归遍历还可以合理利用栈的性质来实现,与上面的稍有不同。
前序:
- public List<Integer> preorderTraversal(TreeNode root) {
- ArrayList<Integer> list = new ArrayList<Integer>();
- Stack<TreeNode> stk = new Stack<>();
- stk.push(root);
- while(!stk.isEmpty()){
- TreeNode node = stk.pop();
- if(node==null)
- continue;
- list.add(node.val);
- stk.push(node.right);
- stk.push(node.left);
- }
- return list;
- }
后序:
- public List<Integer> postorderTraversal(TreeNode root) {
- LinkedList<Integer> list = new LinkedList<Integer>();
- Stack<TreeNode> stk = new Stack<>();
- stk.push(root);
- while(!stk.isEmpty()){
- TreeNode node = stk.pop();
- if(node==null)
- continue;
- list.addFirst(node.val); //LinkedList's method. If using ArrayList here,then using 'Collections.reverse(list)'' in the end;
- stk.push(node.left);
- stk.push(node.right);
- }
- return list;
- }
层序遍历
合理利用队列的性质即可。
- public void levelOrder() {
- BiTNode<E> node =root;
- LinkedList<BiTNode<E>> list = new LinkedList<>();
- list.add(node);
- while(!list.isEmpty()) {
- node=list.poll();
- System.out.print(node.data);
- if(node.lchild!=null)
- list.offer(node.lchild);
- if(node.rchild!=null)
- list.offer(node.rchild);
- }
- }
完整代码(含测试代码)
- package BiTree;
- import java.util.LinkedList;
- import java.util.Stack;
- class BiTNode<E>{
- E data;
- BiTNode<E> lchild,rchild;
- public BiTNode(E data) {
- this.data=data;
- this.lchild=null;
- this.rchild=null;
- }
- }
- public class BiTree<E> {
- private BiTNode<E> root;
- public BiTree() {
- //root=new BiTNode(null, null, null);
- root=null;
- }
- /*
- * 前序遍历
- */
- public void preOrder() {
- preOrderTraverse(root);
- System.out.println();
- }
- private void preOrderTraverse(BiTNode<E> node) {
- if(node==null)
- return;
- System.out.print(node.data);
- preOrderTraverse(node.lchild);
- preOrderTraverse(node.rchild);
- }
- /*
- * 中序遍历
- */
- public void inOrder() {
- inOrderTraverse(root);
- System.out.println();
- }
- private void inOrderTraverse(BiTNode<E> node) {
- if(node==null)
- return;
- inOrderTraverse(node.lchild);
- System.out.print(node.data);
- inOrderTraverse(node.rchild);
- }
- /*
- * 后序遍历
- */
- public void postOrder() {
- postOrderTraverse(root);
- System.out.println();
- }
- private void postOrderTraverse(BiTNode<E> node) {
- if(node==null)
- return;
- postOrderTraverse(node.lchild);
- postOrderTraverse(node.rchild);
- System.out.print(node.data);
- }
- //===============循环遍历===============
- /**
- * 前序遍历(非递归)
- */
- public void preOrder2() {
- preOrder2(root);
- System.out.println();
- }
- private void preOrder2(BiTNode node) {
- Stack<BiTNode> stack = new Stack<BiTNode>();
- while(node!=null||!stack.isEmpty()) {
- while(node!=null) {
- System.out.print(node.data);
- stack.push(node);
- node=node.lchild;
- }
- node=stack.pop().rchild;
- }
- }
- /**
- * 中序遍历
- */
- public void inOrder2() {
- inOrder2(root);
- System.out.println();
- }
- private void inOrder2(BiTNode node) {
- Stack<BiTNode> stack = new Stack<BiTNode>();
- while(node!=null||!stack.isEmpty()) {
- while(node!=null) {
- stack.push(node);
- node=node.lchild;
- }
- node=stack.pop();
- System.out.print(node.data);
- node=node.rchild;
- }
- }
- /**
- * 后序遍历
- */
- public void postOrder2() {
- postOrder2(root);
- System.out.println();
- }
- private void postOrder2(BiTNode node) {
- Stack<BiTNode> stack = new Stack<BiTNode>();
- Stack<Integer> tag = new Stack<Integer>();
- // while(node!=null||!stack.isEmpty()) {
- // while(node!=null){
- // stack.push(node);
- // tag.push(0);
- // node=node.lchild;
- // }
- //这里的tag用于标记当前结点是否完成左右子结点遍历(所以用0,1表示)
- // while(!tag.isEmpty()&&tag.peek()==1) { //栈顶节点的左右子结点已完成遍历
- // System.out.print(stack.pop().data);
- // tag.pop();
- // }
- // if(!tag.isEmpty()) { //上面和这里的 !flag.isEmpty() 不可省略,不然会出错。
- // tag.pop();
- // tag.push(1);
- // node=stack.peek().rchild;
- // }
- // }
- /*后序遍历时,分别从左子树和右子树共两次返回根结点(用tag表示次数),
- * 只有从右子树返回时才访问根结点,所以增加一个栈标记到达结点的次序。
- */
- while(node!=null||!stack.isEmpty()) {
- if(node!=null){
- stack.push(node);
- tag.push(1); //第一次访问
- node=node.lchild;
- }else {
- if(tag.peek()==2) {
- System.out.print(stack.pop().data);
- tag.pop();
- }else {
- tag.pop();
- tag.push(2); //第二次访问
- node=stack.peek().rchild;
- }
- }
- }
- }
- //=========层序遍历============
- public void levelOrder() {
- BiTNode<E> node =root;
- LinkedList<BiTNode<E>> list = new LinkedList<>();
- list.add(node);
- while(!list.isEmpty()) {
- node=list.poll();
- System.out.print(node.data);
- if(node.lchild!=null)
- list.offer(node.lchild);
- if(node.rchild!=null)
- list.offer(node.rchild);
- }
- }
- public static void main(String[] args) {
- BiTree<String> aBiTree = new BiTree<String>();
- aBiTree.root=new BiTNode<String>("A");
- aBiTree.root.lchild=new BiTNode<String>("B");
- aBiTree.root.rchild=new BiTNode<String>("C");
- aBiTree.root.lchild.rchild=new BiTNode<String>("D");
- // BiTree<String> aBiTree = new BiTree<String>();
- // aBiTree.root=new BiTNode("A");
- // aBiTree.root.lchild=new BiTNode("B");
- // aBiTree.root.lchild.lchild=new BiTNode("C");
- // aBiTree.root.lchild.lchild.lchild=new BiTNode("D");
- // aBiTree.root.lchild.rchild=new BiTNode("E");
- // aBiTree.root.lchild.rchild.lchild=new BiTNode("F");
- // aBiTree.root.lchild.rchild.lchild.rchild=new BiTNode("G");
- // aBiTree.root.lchild.rchild.lchild.rchild.rchild=new BiTNode("H");
- System.out.println("————前序————");
- aBiTree.preOrder();
- aBiTree.preOrder2();
- System.out.println("————中序————");
- aBiTree.inOrder();
- aBiTree.inOrder2();
- System.out.println("————后序————");
- aBiTree.postOrder();
- aBiTree.postOrder2();
- System.out.println("————层序遍历————");
- aBiTree.levelOrder();
- }
- }
- ————前序————
- ABDC
- ABDC
- ————中序————
- BDAC
- BDAC
- ————后序————
- DBCA
- DBCA
- ————层序遍历————
- ABCD
遍历结果
【Java】 二叉树的遍历(递归与循环+层序遍历)的更多相关文章
- 二叉树(前序,中序,后序,层序)遍历递归与循环的python实现
二叉树的遍历是在面试使比较常见的项目了.对于二叉树的前中后层序遍历,每种遍历都可以递归和循环两种实现方法,且每种遍历的递归实现都比循环实现要简洁.下面做一个小结. 一.中序遍历 前中后序三种遍历方法对 ...
- Java实现 LeetCode 429 N叉树的层序遍历
429. N叉树的层序遍历 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右,逐层遍历). 例如,给定一个 3叉树 : 返回其层序遍历: [ [1], [3,2,4], [5,6] ] 说明 ...
- Java二叉树实现及递归与非递归遍历实现
树的遍历分两种:1.深度优先遍历 1.1 递归算法实现 2.2 非递归算法实现(使用栈存储)2.广度优先遍历(使用队列存储) import java.util.*; /** * 类功能描述: 二叉树遍 ...
- 【LeetCode-面试算法经典-Java实现】【107-Binary Tree Level Order Traversal II(二叉树层序遍历II)】
[107-Binary Tree Level Order Traversal II(二叉树层序遍历II)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a ...
- c++智能指针和二叉树(1): 图解层序遍历和逐层打印二叉树
二叉树是极为常见的数据结构,关于如何遍历其中元素的文章更是数不胜数. 然而大多数文章都是讲解的前序/中序/后序遍历,有关逐层打印元素的文章并不多,已有文章的讲解也较为晦涩读起来不得要领.本文将用形象的 ...
- 二叉树的层序遍历(levelordertraverse)
数据结构关于二叉树的遍历还有一种层序遍历,按层次依次输出元素.最上层最先输出,同层中最左最先输出,使用队列这一结构来实现: int levelOrderTraverse(IDTree *pTree) ...
- Java 二叉树遍历相关操作
BST二叉搜索树节点定义: /** * BST树的节点类型 * @param <T> */ class BSTNode<T extends Comparable<T>&g ...
- PTA 树的遍历(根据后序中序遍历输出层序遍历)
给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列.这里假设键值都是互不相等的正整数. 输入格式:输入第一行给出一个正整数N(≤30),是二叉树中结点的个数.第二行给出其后序遍历序列.第 ...
- L2-006 树的遍历 (层序遍历)
根据访问根节点与左右子树的先后顺序,二叉树一般有三种遍历方式:先序遍历.中序遍历和后序遍历. 只要给定中序遍历序列与先序或后序中的一种,可以还原二叉树结构.学习数据结构课程时,一直都只会手动构建还原二 ...
随机推荐
- 【bzoj1030】 JSOI2007—文本生成器
http://www.lydsy.com/JudgeOnline/problem.php?id=1030 (题目链接) 题意 给出$n$个单词,问有多少个长度为$m$的文本中至少包含一个单词. Sol ...
- 【HDU5687】Trie
题目大意:需要维护一个支持以下操作的数据结构:(1)支持插入一个字符串(2)支持删除所有前缀等于给定字符串的单词(3)查询该数据结构中是否存在一个以给定字符串为前缀的字符串 题解:由题目可知,需要维护 ...
- jQuery EasyUI API 中文文档 - 消息框(Messager)
http://www.cnblogs.com/Philoo/archive/2011/11/15/jeasyui_api_messager.html Messager 消息框 博客园 风流涕淌 (p ...
- Controller、Service、Dao进行Junit单元
原文链接:http://blog.csdn.net/u013041642/article/details/71430293 Spring对Controller.Service.Dao进行Junit单元 ...
- SQL Server 性能优化详解
故事开篇:你和你的团队经过不懈努力,终于使网站成功上线,刚开始时,注册用户较少,网站性能表现不错,但随着注册用户的增多,访问速度开始变慢,一些用户开始发来邮件表示抗议,事情变得越来越糟,为了留住用户, ...
- 位运算符和unity Layers
按位运算符:与(&).非(~).或(|).异或(^).<<(左移).>>(右移).位运算符主要用来对二进制位进行操作. 逻辑运算符:&&.||.!.逻辑 ...
- bzoj千题计划236:bzoj2300: [HAOI2011]防线修建
http://www.lydsy.com/JudgeOnline/problem.php?id=2300 维护动态凸包,人懒用的set 用叉积判断,不要用斜率 #include<set> ...
- 数学:拓展Lucas定理
拓展Lucas定理解决大组合数取模并且模数为任意数的情况 大概的思路是把模数用唯一分解定理拆开之后然后去做 然后要解决的一个子问题是求模质数的k次方 将分母部分转化成逆元再去做就好了 这里贴一份别人的 ...
- 关于MYSQL group by 分组按时间取最大值的实现方法
类如 有一个帖子的回复表,posts( id , tid , subject , message , dateline ) , id 为 自动增长字段, tid为该回复的主题帖子的id(外键关联), ...
- 第6月第19天 lua动态链接库(luaopen_*函数的使用) skynet
1. 给这个测试库取名为dylib,它包含一个函数add.lua中这样使用: local dylib = require "dylib.test" local c = dyl ...