zoukankan      html  css  js  c++  java
  • 二叉树遍历

    1. 定义

    分三种:

    1. 先序遍历:先访问根节点,然后是左孩子,然后是右孩子(根,左,右)
    2. 中序遍历:左,根,右
    3. 后序遍历:左,右,根
    4. 层次遍历:从根节点开始,从上至下逐层遍历,同一层中,按从左至右顺序遍历

    2. 递归解法

    树表现为一种链表结构,链表问题大都可以采用递归实现。树更是常常有递归解法。

    先、中、后遍历的递归写法同定义一致,再次不在赘述,可参照后边的代码理解。

    层次遍历用递归好像不太直观吧,一般都是用队列迭代,具体也在下边介绍。

    3. 非递归解法---迭代法

    递归解法一般都对应有非递归解法(用栈来模拟递归过程,实现迭代)。

    并非所有程序设计语言都允许递归;此外,大量递归可能造成栈溢出,所以有时需要提供非递归解法,即迭代解法,效率更高一些。

    先、中、后遍历,在遍历节点时经过的路径其实是一样的,只是访问时机不同:从根节点沿左子树深入下去,深入不下去就返回,再从刚才深入时的右子树开始,继续之前的深入和返回。直到最后从根节点的右子树返回根节点为止

    1. 先序遍历:深入时,遇到节点就访问-------节点不空,入栈访问,遍历左子树;否则遍历右子树
    2. 中序遍历:从左子树返回时访问-----------节点不空,遍历左子树;否则出栈访问,遍历右子树
    3. 后续遍历:从右子树返回时访问-----------节点不空,遍历左子树;否则,如果是从左子树返回,遍历右子树,如果是从右子树返回,出栈访问

    中序和后序看着差不多,而实现起来后序遍历略复杂(可能因为中序遍历完右子树就结束了,没有操作了,但是后序遍历完左子树和右子树都有操作,而且操作还不同),需要标志是否右子树都被访问了。可以对每个节点加一个标志位,标志右子树是否被访问了,也可以用一个变量来表示,具体看实现代码。

    层次遍历:采用队列,将根节点入队列。队列不空时,取队首节点访问,并将队首节点的所有子节点入队列。直至队列为空。

    参考资料:http://www.cztvu.ah163.net/czcai/soft/kj/sjjg/jj/ch6.htm

    代码:

      1 package BinaryTree;
      2 
      3 import java.util.ArrayDeque;
      4 import java.util.Deque;
      5 import java.util.List;
      6 import java.util.Scanner;
      7 
      8 /**
      9  * @author 
     10  * @date 2015年9月16日
     11  */
     12 
     13 class TreeNode{
     14     public int val;
     15     public TreeNode left;
     16     public TreeNode right;
     17     
     18     public TreeNode( int val ){
     19         this.val = val;
     20     }
     21     
     22     public static TreeNode createTree(){
     23         Scanner in = new Scanner( System.in );
     24         TreeNode root = null;
     25         int val = in.nextInt();
     26         if( val != '#' ){
     27             root = new TreeNode(val);
     28             root.left = createTree();
     29             root.right = createTree();
     30         }
     31         in.close();
     32         return root;
     33     }
     34     
     35     //the recursion version of preOrder
     36     public void preOrderRec( TreeNode root, List<Integer> res ){
     37         if( root != null ){
     38             res.add(root.val);
     39             preOrderRec( root.left, res );
     40             preOrderRec( root.right, res );
     41         }
     42     }
     43     
     44     //the recursion version of inOrder
     45     public void inOrderRec( TreeNode root, List<Integer> res ){
     46         if( root != null ){
     47             inOrderRec( root.left, res );
     48             res.add( root.val );
     49             inOrderRec( root.right, res );
     50         }
     51     }
     52     
     53     //the recursion version of postOrder
     54     public void postOrderRec( TreeNode root, List<Integer> res ){
     55         if( root != null ){
     56             postOrderRec( root.left, res );
     57             res.add( root.val );
     58             postOrderRec( root.right, res );
     59         }
     60     }
     61     
     62     /*
     63      * the non-recursion version of preOrder using stack.  
     64      * When present node (present root) is not null, push and traverse left subtree.
     65      * Visit when push.
     66      * When present node (present root) is null, pop and traverse right subtree.
     67      */
     68     public void preOrder( TreeNode root, List<Integer> res ){
     69         Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
     70         TreeNode p = root;
     71         while( p!=null || !stack.isEmpty() ){
     72             if( p != null ){
     73                 stack.push(p);
     74                 //visit root-----1
     75                 res.add(p.val);
     76                 //traverse the left subTree-----2
     77                 p = p.left;
     78             }
     79             else{
     80                 p = stack.pop();
     81                 //traverse the right subTree-----3
     82                 p = p.right;
     83             }
     84         }
     85     }
     86     
     87     //the non-recursion version of inOrder using stack. Similar to preOrder except that it visits when pop.
     88     public void inOrder( TreeNode root, List<Integer> res ){
     89         Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
     90         TreeNode p = root;
     91         while( p != null || !stack.isEmpty() ){
     92             if( p != null ){
     93                 stack.push(p);
     94                 //traverse the left subtree------1
     95                 p = p.left;
     96             }
     97             else{
     98                 p = stack.pop();
     99                 //visit the root------2
    100                 res.add(p.val);
    101                 //traverse the right subtree-----3
    102                 p = p.right;
    103             }
    104         }
    105     }
    106     
    107     /*
    108      * the non-recursion version of postOrder using stack. This is more complicated. It only visits when return from the right subree.
    109      * When present node (present root) is not null, push and traverse the left subtree
    110      * When present node (present root) is null, pop.
    111      *     (1)If only the left subtree is visited, then push the right subtree.
    112      *     (2)Else, that is, both the left and right subtree are visited, then visit when pop.
    113      * 
    114      * First implementation (after pushed, the root is in fact traversed twice: once when return from left, once when return from right.
    115      * So we can try to push and pop every root twice):
    116      * For the above (1) step, push the present root again and traverse the right subtree. 
    117      * For the above (2) step, visit when the second pop.
    118      */
    119     public void postOrder1( TreeNode root, List<Integer> res ){
    120         Deque<TreeNodeWithTag> stack = new ArrayDeque<TreeNodeWithTag>();
    121         TreeNode p = root;
    122         while( p != null || !stack.isEmpty() ){
    123             if( p != null ){
    124                 //first push
    125                 stack.push( new TreeNodeWithTag( p, false) );
    126                 //traverse the left subtree-----1
    127                 p = p.left;
    128             }
    129             else{
    130                 //pop
    131                 TreeNodeWithTag top = stack.pop();
    132                 if( !top.tag ){
    133                     //second push
    134                     top.tag = true;
    135                     stack.push(top);
    136                     //traverse the right subtree------2
    137                     p = top.node.right;
    138                 }
    139                 else{
    140                     //visit the root------3
    141                     res.add(top.node.val);
    142                 }
    143             }
    144         }
    145     }
    146     
    147     /*
    148      * The second implementation of postOrder. Similar to postOrder1 using the assistant tag for every node.
    149      * When the present node is not null, push to traverse the left nodes;
    150      * If present node is null, if top.right has not been visited, traverse the right subtree
    151      * Else if top.right has been visited, pop and visit the root
    152      */
    153     public void postOrder2( TreeNode root, List<Integer> res ){
    154         Deque<TreeNodeWithTag> stack = new ArrayDeque<TreeNodeWithTag>();
    155         TreeNode p = root;
    156         while( p != null || !stack.isEmpty() ){
    157             while( p != null ){
    158                 //traverse the left nodes
    159                 stack.push( new TreeNodeWithTag( p, false) );
    160                 p = p.left;
    161             }
    162             if( !stack.isEmpty() && !stack.peek().tag ){
    163                 //traverse the right nodes
    164                 stack.peek().tag = true;
    165                 p = stack.peek().node.right;
    166             }
    167             else if( !stack.isEmpty() ){
    168                 //visit the root
    169                 res.add( stack.pop().node.val );
    170             }
    171         }
    172     }
    173     /*
    174      * The third implementation of postOrder. Use only one tag to check the previous condition.
    175      * If no return, traverse the left subtree
    176      * Else if return from left, traverse the right subtree
    177      * else if return from right, visit the root
    178      */
    179     public void postOrder3( TreeNode root, List<Integer> res ){
    180         Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
    181         boolean rightVisited = false;
    182         TreeNode p = root;
    183         while( p != null || !stack.isEmpty() ){
    184             if( p != null ){
    185                 //traverse the left subtree
    186                 stack.push(p);
    187                 p = p.left;
    188                 rightVisited = false;
    189             }
    190             else if( !rightVisited ){
    191                 //traverse the right subtree
    192                 p = stack.peek().right;
    193                 rightVisited = true;
    194             }
    195             else if( rightVisited ){
    196                 //visit the root
    197                 TreeNode top = stack.pop();
    198                 res.add( top.val );
    199                 if( !stack.isEmpty() && stack.peek().left == top )
    200                     rightVisited = false;
    201             }            
    202         }
    203     }
    204     
    205     /*
    206      * The fourth implementation of postOrder. Use only one tag to check the previous condition.
    207      */
    208     public void postOrder4( TreeNode root, List<Integer> res ){
    209         Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
    210         boolean rightVisited = false;
    211         TreeNode p = root;
    212         while( p!=null || !stack.isEmpty() ){
    213             if( p!=null ){
    214                 //traverse the left subtree
    215                 do{
    216                     stack.push(p);
    217                     p = p.left;                    
    218                 }while( p!=null );
    219                 rightVisited = false;
    220             }
    221             if( !rightVisited ){
    222                 //traverse the right subtreee
    223                 p = stack.peek().right;
    224                 rightVisited = true;
    225             }
    226             else{
    227                 //visit the root
    228                 TreeNode top = stack.pop();
    229                 res.add( top.val );
    230                 if( !stack.isEmpty() && stack.peek().left == top )
    231                     rightVisited = false;
    232             }
    233         }
    234     }
    235     //level order. Use queue.
    236     public void levelOrder( TreeNode root, List<Integer> res ){
    237         Deque<TreeNode> queue = new ArrayDeque<TreeNode>();
    238         queue.add(root);
    239         while( !queue.isEmpty() ){
    240             TreeNode p = queue.remove();
    241             res.add(p.val);    //visit up level
    242             if( p.left != null )    queue.add(p.left);
    243             if( p.right != null )    queue.add(p.right);
    244         }
    245     }
    246     
    247 }
    248 
    249 //used by postOrder1 and postOrder to tag if the left subtree or the right subtree is visited.
    250 class TreeNodeWithTag{
    251     TreeNode node;
    252     boolean tag;    //false represents return from left subtree (the first push and pop), true represents return from the right subtree (the second push and pop)
    253     public TreeNodeWithTag( TreeNode node, boolean value ){
    254         this.node = node;
    255         this.tag = value;        
    256     }
    257 }
    View Code
    
    
  • 相关阅读:
    关于游戏
    学习lucene5.5.4的笔记
    lucene中文学习地址推荐
    lucene的使用与优化
    进一步了解this和super
    被遗忘的设计模式——空对象模式(Null Object Pattern)
    Java 空对象设计模式(Null Object Pattern) 讲解
    java的动态代理机制详解
    为什么要使用代理模式
    大O 表示法
  • 原文地址:https://www.cnblogs.com/hf-cherish/p/4821681.html
Copyright © 2011-2022 走看看