zoukankan      html  css  js  c++  java
  • 二叉树的前序、中序、后序的非递归遍历实现

    一,二叉树的遍历

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

    本程序使用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("
    pre order");
            mbt.preOrder();
            System.out.println();
            mbt.nonRecurPreTraverse();
            
            System.out.println("
     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)

  • 相关阅读:
    愚蠢的程序员...
    云计算优于终端计算和集中计算?
    REST资源合集
    龙芯软件开发:使用龙芯2e的模拟器GXemul
    The Origins of Complex Numbers
    net 3.5 Ms Chart 使用心得
    XPO 第三方控件学习(DevExpress Persistent Object )系列表间关系
    show your data
    缩略数据
    单片机试题
  • 原文地址:https://www.cnblogs.com/hapjin/p/5679482.html
Copyright © 2011-2022 走看看