二叉树的前序、中序、后序的非递归遍历实现

一,二叉树的遍历

二叉树的递归遍历非常简洁,递归调用需要用到栈。因此,要想实现非递归遍历,就类似于模拟程序的自动压栈、出栈,就需要创建一个栈。

本程序使用java.util.LinkedList 来表示栈。

 

二,前序非递归遍历实现

先序遍历是先访问该结点,再访问左子树,然后再访问右子树

因此,先访问该结点;然后将该结点入栈。(第10行)

然后,不断遍历该结点的左孩子(左左孩子....)(第8行while循环),当走到空时(第8行while不成立)。说明最“里层”的结点的左子树已经访问完毕

于是,接着访问它的左子树中的结点(第15行的 if 语句块中的第18行)。当找到它的右孩子之后,又按照前面的步骤遍历左孩子(左左孩子...)(回到第6行的大while循环,首先判断第8行的while循环)

第8行的while循环表明:结点还有左孩子...

第15行的 if 表示:结点的左孩子为空了,需要“切换”到右孩子的路径上去了(再优先访问 右孩子的 左孩子...)

 1 private void nonRecurPreTraverse(BinaryNode root){
 2         LinkedList<BinaryNode> stack = new LinkedList<MyBinaryTree.BinaryNode>();
 3         BinaryNode currentNode;
 4         BinaryNode tmp;
 5         currentNode = root;
 6         while(currentNode != null || !stack.isEmpty())
 7         {
 8             while(currentNode != null)//一直往一个方向走
 9             {
10                 System.out.print(currentNode.ele + " ");//visit
11                 stack.push(currentNode);
12                 currentNode = currentNode.left;
13             }
14             
15             if(!stack.isEmpty())//变换方向
16             {
17                 tmp = stack.pop();
18                 currentNode = tmp.right;
19             }
20         }
21     }

 

前序的递归实现:(基准条件一定不能忘,这是递归的结束条件。)

1     private void preorder(BinaryNode root){
2         if(root == null)
3             return;//base condition
4         System.out.print(root.ele + " ");//visit
5         preorder(root.left);
6         preorder(root.right);
7     }

 

三,中序遍历的非递归实现

先一直沿着“左孩子方向”不断地走,当走到了最左下结点时(第9行while不成立),准备出栈,访问该结点。(第15行if语句)

当出栈访问完该结点(第18、19行)之后,切换到该结点的左孩子的“子树”中,回到第6行大循环,与前面一样,继续对该“子树”先沿着“左孩子方向”不断地走....

 1     private void nonRecurInTraverse(BinaryNode root){
 2         LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>();
 3         BinaryNode currentNode, tmp;
 4         currentNode = root;
 5         
 6         while(currentNode != null || !stack.isEmpty())
 7         {
 8             //先"走完"左孩子
 9             while(currentNode != null)
10             {
11                 stack.push(currentNode);
12                 currentNode = currentNode.left;
13             }
14             //结点没有左孩子了,出栈,访问结点
15             if(!stack.isEmpty())
16             {
17                 tmp = stack.pop();
18                 System.out.print(tmp.ele + " ");//visit
19                 currentNode = tmp.right;
20             }
21         }
22     }

 

中序的递归遍历:

1     private void inorder(BinaryNode root){
2         if(root == null)
3             return;
4         inorder(root.left);
5         System.out.print(root.ele + " ");//visit
6         inorder(root.right);
7     }

 

四,后序遍历的非递归实现

后序遍历的非递归实现比前序、中序的非递归实现 要复杂一点。需要一个标识来标记某结点是否第一次位于栈顶(该结点的左子树已经遍历完毕,从左子树返回准备遍历它的右子树)

对于后序遍历而言,结点的左右子树都遍历完成之后,才访问该结点。某结点会两次位于栈顶,第一次是该结点的左子树都遍历完了,然后 获取 栈顶结点,切换到该结点的右孩子,准备遍历的右子树,当该结点的右子树也都遍历完后,就会第二次位于栈顶,此时将栈顶元素出栈

 1     private void postNonRecurTraverse(BinaryNode root){
 2         LinkedList<BinaryNode> stack = new LinkedList<MyBinaryTree.BinaryNode>();
 3         
 4         BinaryNode currentNode, tmp;
 5         currentNode = root;
 6         while(currentNode != null || !stack.isEmpty())
 7         {
 8             while(currentNode != null)
 9             {
10                 stack.push(currentNode);
11                 currentNode = currentNode.left;
12             }
13             if(!stack.isEmpty())
14             {
15                 tmp = stack.getFirst();
16                 //从左子树返回,需要判断它的右子树是否已经访问了
17                 if(tmp.isFirst == false)//右子树还未被访问
18                 {
19                     tmp.isFirst = true;
20                     currentNode = tmp.right;
21                 }
22                 else{//左右子树都已经访问了
23                     tmp = stack.pop();
24                     System.out.print(tmp.ele + " ");//visit
25 //                    currentNode = null;
26                 }
27             }
28         }//while
29     }

 

对于后序遍历而言,需要判断某个结点第一次位于栈顶,因此上面方法需要在结点类中添加一个boolean 属性表示该节点是否第一次位于栈顶。

class BinaryNode{
    BinaryNode left;
    BinaryNode right;
    int ele;
    boolean isFirst;

    public BinaryNode(int ele)
    {
        this.ele = ele;
        left = right = null;
        isFirst = false;  
     }
}

 

五,整个程序完整实现:

buildTree()方法是根据一维整型数组 随机构造一棵二叉树。然后,对该二叉树进行各种遍历操作。关于如何构建二叉树,可参考:二叉查找树的递归实现及递归分析

import java.util.LinkedList;
import java.util.Random;


/**
 * 
 * @author psj
 *
 */
public class MyBinaryTree {
    private static final Random rand = new Random();//insert left or right
    
    private static class BinaryNode{
        int ele;
        BinaryNode left;
        BinaryNode right;
        boolean isFirst;
        
        public BinaryNode(int ele) {
            this.ele = ele;
            this.left = this.right = null;
            this.isFirst = false;
        }
    }
    
    private BinaryNode root;//二叉树的根结点
    
    //随机构建二叉树
    public void buildTree(){
        int[] ndoes = {3,0,7,4,9,10,45};
        for (int i : ndoes) {
            insert(i);
        }
    }
    public BinaryNode insert(int ele){
        return root = insert(root, ele);
    }
    private BinaryNode insert(BinaryNode root, int ele){
        if(root == null)
            return root = new BinaryNode(ele);
        if(rand.nextInt() %2 == 0)
            root.left = insert(root.left, ele);
        else
            root.right = insert(root.right, ele);
        return root;
    }
    
    //中序非递归遍历
    public void nonRecurInTraverse(){
        if(root == null)
            return;
        nonRecurInTraverse(root);
    }
    private void nonRecurInTraverse(BinaryNode root){
        LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>();
        BinaryNode currentNode, tmp;
        currentNode = root;
        
        while(currentNode != null || !stack.isEmpty())
        {
            //
            while(currentNode != null)
            {
                stack.push(currentNode);
                currentNode = currentNode.left;
            }
            //
            if(!stack.isEmpty())
            {
                tmp = stack.pop();
                System.out.print(tmp.ele + " ");//visit
                currentNode = tmp.right;
            }
        }
    }
    //中序递归遍历
    public void inorder(){
        inorder(root);
    }
    private void inorder(BinaryNode root){
        if(root == null)
            return;
        inorder(root.left);
        System.out.print(root.ele + " ");//visit
        inorder(root.right);
    }
    //先序非递归遍历
    public void nonRecurPreTraverse(){
        if(root == null)
            return;
        nonRecurPreTraverse(root);
    }
    private void nonRecurPreTraverse(BinaryNode root){
        LinkedList<BinaryNode> stack = new LinkedList<MyBinaryTree.BinaryNode>();
        BinaryNode currentNode;
        BinaryNode tmp;
        currentNode = root;
        while(currentNode != null || !stack.isEmpty())
        {
            while(currentNode != null)
            {
                System.out.print(currentNode.ele + " ");//visit
                stack.push(currentNode);
                currentNode = currentNode.left;
            }
            
            if(!stack.isEmpty())
            {
                tmp = stack.pop();
                currentNode = tmp.right;
            }
        }
    }
    //先序递归遍历
    public void preOrder(){
        preorder(root);
    }
    private void preorder(BinaryNode root){
        if(root == null)
            return;//base condition
        System.out.print(root.ele + " ");//visit
        preorder(root.left);
        preorder(root.right);
    }
    //后序非递归遍历
    public void postNonRecurTraverse(){
        if(root == null)
            return;
        postNonRecurTraverse(root);
    }
    private void postNonRecurTraverse(BinaryNode root){
        LinkedList<BinaryNode> stack = new LinkedList<MyBinaryTree.BinaryNode>();
        
        BinaryNode currentNode, tmp;
        currentNode = root;
        while(currentNode != null || !stack.isEmpty())
        {
            while(currentNode != null)
            {
                stack.push(currentNode);
                currentNode = currentNode.left;
            }
            if(!stack.isEmpty())
            {
                tmp = stack.getFirst();
                //从左子树返回,需要判断它的右子树是否已经访问了
                if(tmp.isFirst == false)//右子树还未被访问
                {
                    tmp.isFirst = true;
                    currentNode = tmp.right;
                }
                else{//左右子树都已经访问了
                    tmp = stack.pop();
                    System.out.print(tmp.ele + " ");//visit
//                    currentNode = null;
                }
            }
        }//while
    }
    
    public void postOrder(){
        postOrder(root);
    }
    private void postOrder(BinaryNode root){
        if(root == null)
            return;
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.ele + " ");//visit
    }
    
    public static void main(String[] args) {
        MyBinaryTree mbt =  new MyBinaryTree();
        mbt.buildTree();
        System.out.println("in order");
        mbt.nonRecurInTraverse();
        System.out.println();
        mbt.inorder();
        System.out.println("\npre order");
        mbt.preOrder();
        System.out.println();
        mbt.nonRecurPreTraverse();
        
        System.out.println("\n post order");
        mbt.postOrder();
        System.out.println();
        mbt.postNonRecurTraverse();
        
    }
}
View Code

 

六,二叉查找树中序遍历应用

判断一棵树,是否是二叉查找树。采用中序遍历,如果遍历是有序的,则是一棵二叉查找树。代码如下:

import java.util.LinkedList;
import java.util.List;

public class Solution {

    public boolean isValidBST(TreeNode root) {
        LinkedList<TreeNode> stack = new LinkedList<>();
        TreeNode currentNode,tmp;
//        int currentVal = Integer.MIN_VALUE;
        long currentVal = Long.MIN_VALUE;
        currentNode = root;
        while (currentNode != null || !stack.isEmpty()) {
            while (currentNode != null) {
                stack.push(currentNode);
                currentNode = currentNode.left;
            }

            if (!stack.isEmpty()) {
                tmp = stack.pop();
                if (currentVal >= tmp.val) {
                    return false;
                }else {
                    currentVal = tmp.val;
                }
                currentNode = tmp.right;
            }
        }
        return true;
    }

    public List<Integer> inOrderNonRecurse(TreeNode root, List<Integer> nodes) {
        LinkedList<TreeNode> stack = new LinkedList<>();
        TreeNode currentNode, tmp;
        currentNode = root;
        while (currentNode != null || !stack.isEmpty()) {
            while (currentNode != null) {
                stack.push(currentNode);
                currentNode = currentNode.left;
            }

            if (!stack.isEmpty()) {
                tmp = stack.pop();
                nodes.add(tmp.val);
                currentNode = tmp.right;
            }
        }
        return nodes;
    }


    public List<Integer> inOrder(TreeNode root, List<Integer> nodes) {
        if (root == null) {
            return nodes;
        }
        inOrder(root.left, nodes);
        nodes.add(root.val);
        inOrder(root.right, nodes);
        return nodes;
    }

    public static class TreeNode{
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode(int x) {
            val = x;
        }
    }
}

 

参考资料:

JAVA实现二叉树

二叉树的创建算法

二叉树的构造(http://www.cnblogs.com/hapjin/p/5738354.html)

posted @ 2016-07-18 09:45  大熊猫同学  阅读(10497)  评论(0编辑  收藏  举报