码迷,mamicode.com
首页 > 其他好文 > 详细

二叉树遍历

时间:2015-09-19 16:47:52      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:

1. 定义

分三种:

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

2. 递归解法

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

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

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

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

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

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

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

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

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

 

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

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

代码:

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

 

二叉树遍历

标签:

原文地址:http://www.cnblogs.com/hf-cherish/p/4821681.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!