Nonrecursive Traversal of Binary Tree

First I wanna talk about why should we use <code>Stack</code> to implement this algorithm. I think it is due to the FILO feature of Stack, and that really matters and makes sense when you get around with tree stuff. Cause in nonrecursive way we have to remember where we came from, which means we must figure out how should we go back to the root node as we finish visiting the whole subtree. The key to understand and get good command of nonrecursive traversal of binary tree is to demostrate the whole process by your hand. Don't be lazy. :)

I. Preorder Nonrecursive Traversal

1.1 Algorithm

  In recursive way it is easy and simple to go back to the root when we finish handling or visiting the subtree. But it seems more tricky while you're using nonrecursive way, which means you need to find some auxiliary data structure to help you implement those algorithm. So there we go.

  In preorder way of traversing binary tree, we should visit the root first, then go to visit left subtree and visit the right subtree at last. So the most important thing is to bear the visiting order in mind.

  • a. visit the node and push it into stack as you go down along the left subtree untill it reaches the deepest bottom left node.
  • b. pop a node from the top of stack and check whether it owns a right node, and go right if does.
  • c. loop a ~ b until the stack is empty

  Noticing that when to visit the node may help you interpret this algorithm better.

1.2 Code

Talk is cheap, show me the code!    -- Linus Benedict Torvalds

 public class Node<E> {
public E data;
public Node<E> lnode;
public Node<E> rnode; public Node(){}
public Node(E data) {
this.data = data;
}
}
     /**
* preorder nonrecursive traversal with stack
* @param node
* @author sheepcore
*/
public void preOrderStk(Node<E> node) {
if(node == null)
return;
Node<E> root = node;
Stack<Node<E>> stack = new Stack<>();
while (root != null || !stack.isEmpty()){
while (root != null){
visit(root); //visit the root node first then go to left subtree
stack.push(root); //push left node into stack to go back
root = root.lnode;
}
if(!stack.isEmpty()){
root = stack.pop();
if(root.rnode != null) {
root = root.rnode; //visit the right subtree
} else {
root = null; //clear root when it is return from right subtree
}
}
}
}

II. Inorder Nonrecursive Traversal

2.1 Algorithm

  • a. push the node into stack as you go down along the left subtree untill it reaches the deepest bottom left node.
  • b. pop a node from the top of stack and visit it. Then check whether it owns a right node, go right if does.
  • c. loop a ~ b until the stack is empty

2.2 Code

     /**
* inorder non recursive traversal with stack
* @param node
* @author sheepcore
*/
public void inOrderStk(Node<E> node) {
if(node == null)
return;
Node<E> root = node;
Stack<Node<E>> stack = new Stack<>();
while (root != null || !stack.isEmpty()){
while (root != null){
stack.push(root); //go the left bottom of the tree
root = root.lnode;
}
if(!stack.isEmpty()){
root = stack.pop();
visit(root); //visit it
if(root.rnode != null) {
root = root.rnode;
} else {
root = null; //clear root when it is return from right subtree
}
}
}
}

III. Postorder Nonrecursive Traversal

3.1 Algorithm

  It is more tricky and tougher while traversing in postorder way than in preorder or inorder way. Cause we have no idea where it comes from when we go back to the root node. Therefore we got two common solutions: using tags or using two stacks.

  Using tags for each node can help us find out whether it comes from left subtree or right. Tag the node as "LEFT" while visiting the left subtree and change it to "RIGHT" as we finish. Then go right and go back the root and visit it.

  Using two stacks is prolly like this https://www.geeksforgeeks.org/iterative-postorder-traversal/ and check it out :).

3.2 Code

  1.Using tags

     /**
* postorder nonrecursive traversal of binary tree * The key to understand and get good command of this algorithm is to demonstrate the whole processes
* of each step and figure out how the nodes' status changed and for what that will make sense
* to you to permanently beat the algorithm. And you must know that each nodes should be pushed into
* stack twice which seems to be sort of time-consuming, so we can also check whether the nodes has
* right node when we go down alongside the left subtree and that could make the performance better. :)
* @param node
* @author sheepcore
*/
public void postOrderStk(Node<E> node){
if(root == null)
return;
Node<E> root = node;
stkNode<E> s;
Stack<stkNode<E>> stack = new Stack<>();
do {
while (root != null){ //go down along the left branches of the bitree
s = new stkNode<>();
s.node = root;
s.tag = tag.L;
stack.push(s);
root = root.lnode;
}//while-root
boolean continual = true; //flag for continue
while (continual && !stack.isEmpty()) {
s = stack.pop();
root = s.node;
switch (s.tag){
case L: s.tag = tag.R; //return from left subtree
stack.push(s);
continual = false;
root = root.rnode;
break;
case R: visit(root); break; //return from right subtree
}
}//while-continual-stack
}while (!stack.isEmpty());
}

  2.Using two stacks

     /**
* post-order nonrecursive traversal with two stacks
* @param node
*/
public void postOrderStk2(Node<E> node){
if(root == null)
return;
Node<E> root = node;
Stack<Node<E>> s1 = new Stack<>();
Stack<Node<E>> s2 = new Stack<>();
s1.push(root);
while (!s1.isEmpty()){
root = s1.pop();
s2.push(root);
if (root.lnode != null) { s1.push(root.lnode); }
if (root.rnode != null) { s1.push(root.rnode); }
}
while (!s2.isEmpty()){
visit(s2.pop());
}
System.out.println();
}

IV. Levelorder Nonrecursive Traversal

4.1 Algorithm

  In levelorder you need to visit the nodes from left to right and from top to bottom of the tree. Using a queue to implement the algorithm is way more simple as you think.

4.2 Code

    /**
* level order traversal using queue
* 1. check and visit the root node remove from the queue
* 2. add its left and right nodes if does
* 3. loop 1 ~ 2 while queue is empty
* @param root
* @author sheepcore
*/
public void levelOrder(Node<E> root){
if(root == null)
return;
LinkedList<Node<E>> q = new LinkedList<>();
Node<E> cur;
q.addLast(root);
while (!q.isEmpty()) {
cur = q.removeFirst();
visit(cur);
if(cur.lnode != null) {
q.addLast(cur.lnode);
}
if(cur.rnode != null){
q.addLast(cur.rnode);
}
}
}

V. Summary

  哈哈,自己的第一篇全英文博客,最近因为考试在练英文写作,所以干脆就趁热打铁一下。总结一下,这四种二叉树遍历的非递归方法其实总体逻辑不算难,需要自己多在纸上演算推导,感受推导逻辑之后,才能把它转化为代码逻辑,这样写出的代码会更加印象深刻的。其中后序非递归遍历稍微麻烦一点,需要考虑当回溯到根节点时,是从左子树来的呢?还是从右子树呢?因为这两种情况对根节点将执行不同的操作,所以需要特别处理。其实方法还有很多,这里自己只是简单实现了两种最常见的方法:标志位法和双堆栈法。好啦!我得滚去学习了,因为落后就要挨打了!!!

Sometimes people call you an idiot when you do something stupid, keep doing that until you change that stupid things to glory things. And then you can stare at those people's eyes and say, "I made it bitch!". 

数据结构之二叉树篇卷三 -- 二叉树非递归遍历(With Java)的更多相关文章

  1. 二叉树3种递归和非递归遍历(Java)

    import java.util.Stack; //二叉树3种递归和非递归遍历(Java) public class Traverse { /******************一二进制树的定义*** ...

  2. 数据结构二叉树的递归与非递归遍历之java,javascript,php实现可编译(1)java

    前一段时间,学习数据结构的各种算法,概念不难理解,只是被C++的指针给弄的犯糊涂,于是用java,web,javascript,分别去实现数据结构的各种算法. 二叉树的遍历,本分享只是以二叉树中的先序 ...

  3. C++学习---二叉树的输入及非递归遍历

    二叉树的二叉链表存储表示如下 //二叉树的二叉链表存储表示 typedef struct BiTNode { char data;//结点数据域 struct BiTNode* lchild, * r ...

  4. ZT 二叉树的非递归遍历

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

  5. Java实现二叉树的创建、递归/非递归遍历

    近期复习数据结构中的二叉树的相关问题,在这里整理一下 这里包含: 1.二叉树的先序创建 2.二叉树的递归先序遍历 3.二叉树的非递归先序遍历 4.二叉树的递归中序遍历 5.二叉树的非递归中序遍历 6. ...

  6. C++编程练习(17)----“二叉树非递归遍历的实现“

    二叉树的非递归遍历 最近看书上说道要掌握二叉树遍历的6种编写方式,之前只用递归方式编写过,这次就用非递归方式编写试一试. C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历 ...

  7. c/c++二叉树的创建与遍历(非递归遍历左右中,破坏树结构)

    二叉树的创建与遍历(非递归遍历左右中,破坏树结构) 创建 二叉树的递归3种遍历方式: 1,先中心,再左树,再右树 2,先左树,再中心,再右树 3,先左树,再右树,再中心 二叉树的非递归4种遍历方式: ...

  8. JAVA递归、非递归遍历二叉树(转)

    原文链接: JAVA递归.非递归遍历二叉树 import java.util.Stack; import java.util.HashMap; public class BinTree { priva ...

  9. 非递归遍历二叉树Java实现

    2018-10-03 20:16:53 非递归遍历二叉树是使用堆栈来进行保存,个人推荐使用双while结构,完全按照遍历顺序来进行堆栈的操作,当然在前序和后序的遍历过程中还有其他的压栈流程. 一.Bi ...

随机推荐

  1. Android P不能使用http

    三种方法解决Android P(安卓9.0)联网问题: 1.最简单的方法就是改用https,但很多的http接口都要一一改(非全局接口可以忽略方法1). 2.target降低至27,target27之 ...

  2. 前端优化---回流 (reflow)与 重绘(repaint)

    回流(reflow):指的是网络浏览器为了重新渲染部分或全部的文档而重新计算文档中元素的位置和几何结构的过程. 页面上节点是以树的形式展现的,我们通过js将页面上的一个节点删除,此时为了不让剩下的节点 ...

  3. Codeforces 396D

    题意略. 思路: 很经典的逆序对计数问题. https://blog.csdn.net/v5zsq/article/details/79006684 这篇博客讲得很好. 当循环到n的时候,我们需要特殊 ...

  4. Leetcode之广度优先搜索(BFS)专题-详解429. N叉树的层序遍历(N-ary Tree Level Order Traversal)

    Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree Level Order Traversal) 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右 ...

  5. Jmeter 从数据库查询多个字段,依次传给登录接口怎么实现?

    问题背景: 博文“Jmeter 如何把数据库的数据依次获取作为参数传入下一个请求?附栗子”某天有人留言如下: 看了下当时写的文章,如果从数据库查询多个字段,依次传给登录接口,确实不能合理实现,所以,特 ...

  6. java实现截取PDF指定页并进行图片格式转换

    1.引入依赖 <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox& ...

  7. 【百度之星】【java大数+C++做法】hdu 6719 Strassen

    代码:递归搜索一下.java大数做法 import java.util.*; import java.math.*; import java.security.MessageDigest; publi ...

  8. JOBDU 1199 找位置

    题目1199:找位置 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2645 解决:1286 题目描述: 对给定的一个字符串,找出有重复的字符,并给出其位置,如:abcaaAB12ab12 ...

  9. 洛谷 P4206 [NOI2005]聪聪与可可 题解

    题面 输入 数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数. 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号. 接下来E行,每 ...

  10. POJ 2391 Ombrophobic Bovines(Floyd+二分+最大流)

    题目链接 题意:农场有F(1 <= F <= 200)片草地用于放牛,这些草地有P(1 <= P <= 1500)连接,农场的草地上有一些避雨点,奶牛们可以在避雨点避雨,但是避 ...