【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】 二叉树的遍历(递归与循环+层序遍历)的更多相关文章

  1. 二叉树(前序,中序,后序,层序)遍历递归与循环的python实现

    二叉树的遍历是在面试使比较常见的项目了.对于二叉树的前中后层序遍历,每种遍历都可以递归和循环两种实现方法,且每种遍历的递归实现都比循环实现要简洁.下面做一个小结. 一.中序遍历 前中后序三种遍历方法对 ...

  2. Java实现 LeetCode 429 N叉树的层序遍历

    429. N叉树的层序遍历 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右,逐层遍历). 例如,给定一个 3叉树 : 返回其层序遍历: [ [1], [3,2,4], [5,6] ] 说明 ...

  3. Java二叉树实现及递归与非递归遍历实现

    树的遍历分两种:1.深度优先遍历 1.1 递归算法实现 2.2 非递归算法实现(使用栈存储)2.广度优先遍历(使用队列存储) import java.util.*; /** * 类功能描述: 二叉树遍 ...

  4. 【LeetCode-面试算法经典-Java实现】【107-Binary Tree Level Order Traversal II(二叉树层序遍历II)】

    [107-Binary Tree Level Order Traversal II(二叉树层序遍历II)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a ...

  5. c++智能指针和二叉树(1): 图解层序遍历和逐层打印二叉树

    二叉树是极为常见的数据结构,关于如何遍历其中元素的文章更是数不胜数. 然而大多数文章都是讲解的前序/中序/后序遍历,有关逐层打印元素的文章并不多,已有文章的讲解也较为晦涩读起来不得要领.本文将用形象的 ...

  6. 二叉树的层序遍历(levelordertraverse)

    数据结构关于二叉树的遍历还有一种层序遍历,按层次依次输出元素.最上层最先输出,同层中最左最先输出,使用队列这一结构来实现: int levelOrderTraverse(IDTree *pTree) ...

  7. Java 二叉树遍历相关操作

    BST二叉搜索树节点定义: /** * BST树的节点类型 * @param <T> */ class BSTNode<T extends Comparable<T>&g ...

  8. PTA 树的遍历(根据后序中序遍历输出层序遍历)

      给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列.这里假设键值都是互不相等的正整数. 输入格式:输入第一行给出一个正整数N(≤30),是二叉树中结点的个数.第二行给出其后序遍历序列.第 ...

  9. L2-006 树的遍历 (层序遍历)

    根据访问根节点与左右子树的先后顺序,二叉树一般有三种遍历方式:先序遍历.中序遍历和后序遍历. 只要给定中序遍历序列与先序或后序中的一种,可以还原二叉树结构.学习数据结构课程时,一直都只会手动构建还原二 ...

随机推荐

  1. 洛谷 P4284 [SHOI2014]概率充电器 解题报告

    P4284 [SHOI2014]概率充电器 题目描述 著名的电子产品品牌SHOI 刚刚发布了引领世界潮流的下一代电子产品-- 概率充电器: "采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  2. 前端学习 -- Css -- 行间距

    在CSS并没有为我们提供一个直接设置行间距的方式,我们只能通过设置行高来间接的设置行间距,行高越大行间距越大.使用line-height来设置行高 .行高类似于我们上学单线本,单线本是一行一行,线与线 ...

  3. PHP使用serialize和json_encode序列化数据并通过redis缓存文件和$GLOGALS缓存资源对象

    PHP常用缓存方式:第一种,把需要缓存的数据进行处理,形成PHP可以直接执行的文件.在需要缓存数据的时候,通过include方式引入,并使用.第二种,把需要的数据通过serialize函数序列化后直接 ...

  4. c++并发编程之线程的互斥与同步

    什么是线程的同步与互斥? 互斥:指在某一时刻指允许一个进程运行其中的程序片,具有排他性和唯一性. 对于线程A和线程B来讲,在同一时刻,只允许一个线程对临界资源进行操作,即当A进入临界区对资源操作时,B ...

  5. mysql concat_ws 与 concat 多字段模糊匹配应用

    有时我们希望在表中多个字段检索是否有我们给出的关键字,我们可以使用 concat_ws 和 concat 连接需要检索的字段,如: select * from userInfo where conca ...

  6. 笔记 freemark list标签迭代Map<Map<String,Object>集合排序问题

    本博客是自己在学习和工作途中的积累与总结,仅供自己参考,也欢迎大家转载,转载时请注明出处. 工作中出现一个比较特殊的问题,在模板ftl文件中,一般用list迭代map 举例: 后台: // 传入的参数 ...

  7. Phalcon框架之———— 2.0升级到3.0 问题Model验证问题解决

    Github源码:https://github.com/phalcon/cphalcon/tree/master/phalcon/validation/validator Phalcon 2.0 Mo ...

  8. [iOS]Xcode+GitHub远程代码托管(GIT, SVN)

    先来看看什么是代码远程托管: 其实就是将我们的代码上传到GitHub的服务器上, 供别人下载, 当然了也可以在团队开发的时候, 使用GitHub进行代码合并工作, 下面我们进入正题 (已经有远程仓库的 ...

  9. CS229 笔记05

    CS229 笔记05 生成学习方法 判别学习方法的主要思想是假设属于不同target的样本,服从不同的分布. 例如 \(P(x|y=0) \sim {\scr N}(\mu_1,\sigma_1^2) ...

  10. 关于 xcode5 的no matching provisioning profiles found

    CHENYILONG Blog 关于 xcode5 的no matching provisioning prof- about the question in xcode5 "no matc ...