代码改变世界

二叉树的基本遍历方法

2012-07-09 17:16  coodoing  阅读(287)  评论(0编辑  收藏  举报
View Code
  1 package Tree;
  2 
  3 import java.util.Stack;
  4 public class BinaryTreeTraversal {
  5     protected Node root;
  6 
  7     public BinaryTreeTraversal(Node root) {
  8         this.root = root;
  9     }
 10 
 11     public Node getRoot() {
 12         return root;
 13     }
 14 
 15     /** 构造树 */
 16     public static Node init() {
 17         Node a = new Node('A');
 18         Node b = new Node('B', null, a);
 19         Node c = new Node('C');
 20         Node d = new Node('D', b, c);
 21         Node e = new Node('E');
 22         Node f = new Node('F', e, null);
 23         Node g = new Node('G', null, f);
 24         Node h = new Node('H', d, g);
 25         return h;// root  
 26     }
 27 
 28     /** 访问节点 */
 29     public static void visit(Node p) {
 30         System.out.print(p.getKey() + " ");
 31     }
 32 
 33     /** 递归实现前序遍历 */
 34     protected static void preorder(Node p) {
 35         if (p != null) {
 36             visit(p);
 37             preorder(p.getLeft());
 38             preorder(p.getRight());
 39         }
 40     }
 41 
 42     /** 递归实现中序遍历 */
 43     protected static void inorder(Node p) {
 44         if (p != null) {
 45             inorder(p.getLeft());
 46             visit(p);
 47             inorder(p.getRight());
 48         }
 49     }
 50 
 51     /** 递归实现后序遍历 */
 52     protected static void postorder(Node p) {
 53         if (p != null) {
 54             postorder(p.getLeft());
 55             postorder(p.getRight());
 56             visit(p);
 57         }
 58     }
 59 
 60     /**********************************************************************************************/
 61     /** 非递归实现前序遍历 */
 62     protected static void iterativePreorder(Node p) {
 63         Stack<Node> stack = new Stack<Node>();
 64         if (p != null) {
 65             stack.push(p);
 66             while (!stack.empty()) {
 67                 p = stack.pop();
 68                 visit(p);
 69                 //为什么p.getLeft() 在后,getRight()在前应为while 循环第一句就是pop visit所以要把left放上,先访问。之中方法是即压即访问法。
 70                 if (p.getRight() != null)
 71                     stack.push(p.getRight());
 72                 if (p.getLeft() != null) 
 73                     stack.push(p.getLeft());
 74             }
 75         }
 76     }
 77 
 78     /** 非递归实现中序遍历 */
 79     //思路与上面iterativePreorder 一致。
 80     protected static void iterativeInorder(Node p) {
 81         Stack<Node> stack = new Stack<Node>();
 82         while (p != null) {
 83             while (p != null) {
 84                 if (p.getRight() != null)
 85                     stack.push(p.getRight());// 当前节点右子入栈  
 86                 stack.push(p);// 当前节点入栈  
 87                 p = p.getLeft();
 88             }
 89             p = stack.pop();
 90             while (!stack.empty() && p.getRight() == null) {
 91                 visit(p);
 92                 p = stack.pop();
 93             }
 94             visit(p);
 95             if (!stack.empty())
 96                 p = stack.pop();
 97             else
 98                 p = null;
 99         }
100     }
101 
102     /*******************************************************************************************/
103 
104     /*******************************************************************************************/
105     /** 非递归实现前序遍历2 */
106     protected static void iterativePreorder2(Node p) {
107         Stack<Node> stack = new Stack<Node>();
108         Node node = p;
109         while (node != null || stack.size() > 0) {
110             while (node != null) {//压入所有的左节点,压入前访问它。左节点压入完后pop访问右节点。像这样算法时思考规律性的东西在哪。不管哪个节点都要压所节点判断右节点。  
111                 visit(node);
112                 stack.push(node);
113                 node = node.getLeft();
114             }
115             if (stack.size() > 0) {//  
116                 node = stack.pop();
117                 node = node.getRight();
118             }
119         }
120     }
121 
122     /** 非递归实现中序遍历2 */
123     protected static void iterativeInorder2(Node p) {
124         Stack<Node> stack = new Stack<Node>();
125         Node node = p;
126         while (node != null || stack.size() > 0) {
127             while (node != null) {
128                 stack.push(node);
129                 node = node.getLeft();
130             }
131             if (stack.size() > 0) {
132                 node = stack.pop();
133                 visit(node); //与iterativePreorder2比较只有这句话的位置不一样,弹出时再访问。
134                 node = node.getRight();
135             }
136         }
137     }
138 
139     /*******************************************************************************************/
140 
141     /** 非递归实现后序遍历 */
142     protected static void iterativePostorder(Node p) {
143         Node q = p;
144         Stack<Node> stack = new Stack<Node>();
145         while (p != null) {
146             // 左子树入栈  
147             for (; p.getLeft() != null; p = p.getLeft())
148                 stack.push(p);
149             // 当前节点无右子或右子已经输出  
150             while (p != null && (p.getRight() == null || p.getRight() == q)) {
151                 visit(p);
152                 q = p;// 记录上一个已输出节点  
153                 if (stack.empty())
154                     return;
155                 p = stack.pop();
156             }
157             // 处理右子  
158             stack.push(p);
159             p = p.getRight();
160         }
161     }
162 
163     /** 非递归实现后序遍历 双栈法 */
164     protected static void iterativePostorder2(Node p) {
165         //理解左子树   右子树 根递归性质,把它运用到循环当中去。  
166         Stack<Node> lstack = new Stack<Node>();//左子树栈  
167         Stack<Node> rstack = new Stack<Node>();//右子树栈
168         Node node = p, right;
169         do {
170             while (node != null) {
171                 right = node.getRight();
172                 lstack.push(node);
173                 rstack.push(right);
174                 node = node.getLeft();
175             }
176             node = lstack.pop();
177             right = rstack.pop();
178             // 前面已经保证node节点无左节点了
179             if (right == null) {
180                 visit(node);
181             } else {
182                 lstack.push(node);
183                 rstack.push(null);//???
184             }
185             node = right; //继续访问右子树
186         } while (lstack.size() > 0 || rstack.size() > 0);
187     }
188 
189     /** 非递归实现后序遍历 单栈法*/
190     protected static void iterativePostorder3(Node p) {
191         Stack<Node> stack = new Stack<Node>();
192         Node node = p, prev = p;
193         while (node != null || stack.size() > 0) {
194             while (node != null) {
195                 stack.push(node);
196                 node = node.getLeft();
197             }
198             if (stack.size() > 0) {
199                 Node temp = stack.peek().getRight();
200                 if (temp == null || temp == prev) {
201                     node = stack.pop();
202                     visit(node);
203                     prev = node;
204                     node = null;
205                 } else {
206                     node = temp;
207                 }
208             }
209 
210         }
211     }
212 
213     /** 非递归实现后序遍历4 双栈法*/
214     protected static void iterativePostorder4(Node p) {
215         Stack<Node> stack = new Stack<Node>();
216         Stack<Node> temp = new Stack<Node>();
217         Node node = p;
218         while (node != null || stack.size() > 0) {
219             while (node != null) {
220                 temp.push(node);
221                 stack.push(node);
222                 node = node.getRight();
223             }
224             if (stack.size() > 0) {
225                 node = stack.pop();
226                 node = node.getLeft();
227             }
228         }
229         while (temp.size() > 0) {//把插入序列都插入到了temp。
230             node = temp.pop();
231             visit(node);
232         }
233     }
234 
235     /** 
236      * @param args 
237      */
238     public static void main(String[] args) {
239         BinaryTreeTraversal tree = new BinaryTreeTraversal(init());
240         System.out.print(" 递归遍历 \n");
241         System.out.print(" Pre-Order:");
242         preorder(tree.getRoot());
243 
244         System.out.print(" \n In-Order:");
245         inorder(tree.getRoot());
246 
247         System.out.print("\n Post-Order:");
248         postorder(tree.getRoot());
249 
250         System.out.print(" \n非递归遍历");
251         System.out.print(" \n Pre-Order:");
252         iterativePreorder(tree.getRoot());
253 
254         System.out.print("\n Pre-Order2:");
255         iterativePreorder2(tree.getRoot());
256 
257         System.out.print(" \n In-Order:");
258         iterativeInorder(tree.getRoot());
259 
260         System.out.print("\n In-Order2:");
261         iterativeInorder2(tree.getRoot());
262 
263         System.out.print("\n Post-Order:");
264         iterativePostorder(tree.getRoot());
265 
266         System.out.print("\n Post-Order2:");
267         iterativePostorder2(tree.getRoot());
268 
269         System.out.print("\n Post-Order3:");
270         iterativePostorder3(tree.getRoot());
271 
272         System.out.print("\n Post-Order4:");
273         iterativePostorder4(tree.getRoot());
274 
275     }
276 
277 }
278 
279 class Node {
280     private char key;
281     private Node left, right;
282 
283     public Node(char key) {
284         this(key, null, null);
285     }
286 
287     public Node(char key, Node left, Node right) {
288         this.key = key;
289         this.left = left;
290         this.right = right;
291     }
292 
293     public char getKey() {
294         return key;
295     }
296 
297     public void setKey(char key) {
298         this.key = key;
299     }
300 
301     public Node getLeft() {
302         return left;
303     }
304 
305     public void setLeft(Node left) {
306         this.left = left;
307     }
308 
309     public Node getRight() {
310         return right;
311     }
312 
313     public void setRight(Node right) {
314         this.right = right;
315     }
316 }