1、分析
二叉树的深度优先遍历的非递归的通用做法是采用栈,广度优先遍历的非递归的通用做法是采用队列。
深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。要特别注意的是,二叉树的深度优先遍历比较特殊,可以细分为先序遍历、中序遍历、后序遍历。具体说明如下:
- 先序遍历:对任一子树,先访问根,然后遍历其左子树,最后遍历其右子树。
- 中序遍历:对任一子树,先遍历其左子树,然后访问根,最后遍历其右子树。
- 后序遍历:对任一子树,先遍历其左子树,然后遍历其右子树,最后访问根。
广度优先遍历:又叫层次遍历,从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。
2、举例说明
对下图所示的二叉排序树进行遍历,要求使用先序遍历(递归、非递归)、中序遍历(递归、非递归)、后序遍历(递归、非递归)和广度优先遍历。
2.1、参考代码
[java]
1. package BinaryTreeTraverseTest;
2.
3. import java.util.LinkedList;
4. import java.util.Queue;
5.
6. /**
7. * 二叉树的深度优先遍历和广度优先遍历
8. * @author Fantasy
9. * @version 1.0 2016/10/05 - 2016/10/07
10. */
11. public class BinaryTreeTraverseTest {
12. public static void main(String[] args) {
13.
14. new BinarySortTree<Integer>();
15.
16. 35);
17. 20);
18. 15);
19. 16);
20. 29);
21. 28);
22. 30);
23. 40);
24. 50);
25. 45);
26. 55);
27.
28. "先序遍历(递归):");
29. tree.preOrderTraverse(tree.getRoot());
30. System.out.println();
31. "中序遍历(递归):");
32. tree.inOrderTraverse(tree.getRoot());
33. System.out.println();
34. "后序遍历(递归):");
35. tree.postOrderTraverse(tree.getRoot());
36. System.out.println();
37.
38. "先序遍历(非递归):");
39. tree.preOrderTraverseNoRecursion(tree.getRoot());
40. System.out.println();
41. "中序遍历(非递归):");
42. tree.inOrderTraverseNoRecursion(tree.getRoot());
43. System.out.println();
44. "后序遍历(非递归):");
45. tree.postOrderTraverseNoRecursion(tree.getRoot());
46. System.out.println();
47.
48. "广度优先遍历:");
49. tree.breadthFirstTraverse(tree.getRoot());
50. }
51. }
52.
53. /**
54. * 结点
55. */
56. class Node<E extends Comparable<E>> {
57.
58. E value;
59. Node<E> left;
60. Node<E> right;
61.
62. Node(E value) {
63. this.value = value;
64. null;
65. null;
66. }
67.
68. }
69.
70. /**
71. * 使用一个先序序列构建一棵二叉排序树(又称二叉查找树)
72. */
73. class BinarySortTree<E extends Comparable<E>> {
74.
75. private Node<E> root;
76.
77. BinarySortTree() {
78. null;
79. }
80.
81. public void insertNode(E value) {
82. if (root == null) {
83. new Node<E>(value);
84. return;
85. }
86. Node<E> currentNode = root;
87. while (true) {
88. if (value.compareTo(currentNode.value) > 0) {
89. if (currentNode.right == null) {
90. new Node<E>(value);
91. break;
92. }
93. currentNode = currentNode.right;
94. else {
95. if (currentNode.left == null) {
96. new Node<E>(value);
97. break;
98. }
99. currentNode = currentNode.left;
100. }
101. }
102. }
103.
104. public Node<E> getRoot(){
105. return root;
106. }
107.
108. /**
109. * 先序遍历二叉树(递归)
110. * @param node
111. */
112. public void preOrderTraverse(Node<E> node) {
113. " ");
114. if (node.left != null)
115. preOrderTraverse(node.left);
116. if (node.right != null)
117. preOrderTraverse(node.right);
118. }
119.
120. /**
121. * 中序遍历二叉树(递归)
122. * @param node
123. */
124. public void inOrderTraverse(Node<E> node) {
125. if (node.left != null)
126. inOrderTraverse(node.left);
127. " ");
128. if (node.right != null)
129. inOrderTraverse(node.right);
130. }
131.
132. /**
133. * 后序遍历二叉树(递归)
134. * @param node
135. */
136. public void postOrderTraverse(Node<E> node) {
137. if (node.left != null)
138. postOrderTraverse(node.left);
139. if (node.right != null)
140. postOrderTraverse(node.right);
141. " ");
142. }
143.
144. /**
145. * 先序遍历二叉树(非递归)
146. * @param root
147. */
148. public void preOrderTraverseNoRecursion(Node<E> root) {
149. new LinkedList<Node<E>>();
150. null;
151. stack.push(root);
152. while (!stack.isEmpty()) {
153. currentNode = stack.pop();
154. " ");
155. if (currentNode.right != null)
156. stack.push(currentNode.right);
157. if (currentNode.left != null)
158. stack.push(currentNode.left);
159. }
160. }
161.
162. /**
163. * 中序遍历二叉树(非递归)
164. * @param root
165. */
166. public void inOrderTraverseNoRecursion(Node<E> root) {
167. new LinkedList<Node<E>>();
168. Node<E> currentNode = root;
169. while (currentNode != null || !stack.isEmpty()) {
170. // 一直循环到二叉排序树最左端的叶子结点(currentNode是null)
171. while (currentNode != null) {
172. stack.push(currentNode);
173. currentNode = currentNode.left;
174. }
175. currentNode = stack.pop();
176. " ");
177. currentNode = currentNode.right;
178. }
179. }
180.
181. /**
182. * 后序遍历二叉树(非递归)
183. * @param root
184. */
185. public void postOrderTraverseNoRecursion(Node<E> root) {
186. new LinkedList<Node<E>>();
187. Node<E> currentNode = root;
188. null;
189. while (currentNode != null || !stack.isEmpty()) {
190. // 一直循环到二叉排序树最左端的叶子结点(currentNode是null)
191. while (currentNode != null) {
192. stack.push(currentNode);
193. currentNode = currentNode.left;
194. }
195. currentNode = stack.pop();
196. // 当前结点没有右结点或上一个结点(已经输出的结点)是当前结点的右结点,则输出当前结点
197. while (currentNode.right == null || currentNode.right == rightNode) {
198. " ");
199. rightNode = currentNode;
200. if (stack.isEmpty()) {
201. return; //root以输出,则遍历结束
202. }
203. currentNode = stack.pop();
204. }
205. //还有右结点没有遍历
206. currentNode = currentNode.right;
207. }
208. }
209.
210. /**
211. * 广度优先遍历二叉树,又称层次遍历二叉树
212. * @param node
213. */
214. public void breadthFirstTraverse(Node<E> root) {
215. new LinkedList<Node<E>>();
216. null;
217. queue.offer(root);
218. while (!queue.isEmpty()) {
219. currentNode = queue.poll();
220. " ");
221. if (currentNode.left != null)
222. queue.offer(currentNode.left);
223. if (currentNode.right != null)
224. queue.offer(currentNode.right);
225. }
226. }
227.
228. }
2.2、输出结果
先序遍历(递归):35 20 15 16 29 28 30 40 50 45 55
中序遍历(递归):15 16 20 28 29 30 35 40 45 50 55
后序遍历(递归):16 15 28 30 29 20 45 55 50 40 35
先序遍历(非递归):35 20 15 16 29 28 30 40 50 45 55
中序遍历(非递归):15 16 20 28 29 30 35 40 45 50 55
后序遍历(非递归):16 15 28 30 29 20 45 55 50 40 35
广度优先遍历:35 20 40 15 29 50 16 28 30 45 55