标签:
分三种:
树表现为一种链表结构,链表问题大都可以采用递归实现。树更是常常有递归解法。
先、中、后遍历的递归写法同定义一致,再次不在赘述,可参照后边的代码理解。
层次遍历用递归好像不太直观吧,一般都是用队列迭代,具体也在下边介绍。
递归解法一般都对应有非递归解法(用栈来模拟递归过程,实现迭代)。
并非所有程序设计语言都允许递归;此外,大量递归可能造成栈溢出,所以有时需要提供非递归解法,即迭代解法,效率更高一些。
先、中、后遍历,在遍历节点时经过的路径其实是一样的,只是访问时机不同:从根节点沿左子树深入下去,深入不下去就返回,再从刚才深入时的右子树开始,继续之前的深入和返回。直到最后从根节点的右子树返回根节点为止
中序和后序看着差不多,而实现起来后序遍历略复杂(可能因为中序遍历完右子树就结束了,没有操作了,但是后序遍历完左子树和右子树都有操作,而且操作还不同),需要标志是否右子树都被访问了。可以对每个节点加一个标志位,标志右子树是否被访问了,也可以用一个变量来表示,具体看实现代码。
层次遍历:采用队列,将根节点入队列。队列不空时,取队首节点访问,并将队首节点的所有子节点入队列。直至队列为空。
参考资料: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