前序遍历、中序遍历、后续遍历图解以及算法
概述:
本文包含以下算法,大部分以递归实现
前序遍历(中左右):先输出自己,然后是左孩子,最后右孩子;
中序遍历(左中右):先输出左孩子,然后是自己,最后右孩子;
后序遍历(左右中):先输出左孩子,然后是右孩子,最后自己;
层次遍历 :一层一层从上到下从左到右遍历;
前序遍历和中序遍历确定一棵二叉树;
后序遍历和中序遍历确定一棵二叉树;
前序遍历和后续遍历其中一种加上中序遍历,便可以确定一颗二叉树;
以下是关于遍历的算法
1 public class Main {
2 public static void main(String[] args) {
3 /*
4 生成二叉树
5 0
6 1 2
7 3 4 5 6
8 前序遍历为: 0134256
9 中序遍历为: 3140526
10 后序遍历为: 3415620
11 */
12 TreeNode[] tree = new TreeNode[7];
13 for (int i = 0; i < 7; i++) {
14 tree[i] = new TreeNode(i);
15 }
16
17 for (int i = 0; i < 7; i++) {
18 if(i*2+1 < 7){
19 tree[i].left = tree[i*2+1];
20 }
21 if(i*2+2 <7){
22 tree[i].right = tree[i*2+2];
23 }
24 }
25 System.out.println("前序遍历的结果:");
26 preOrder(tree[0]);
27 System.out.println("\n后序遍历的结果:");
28 afterOrder(tree[0]);
29 System.out.println("\n中序遍历的结果:");
30 infixOrder(tree[0]);
31 System.out.println("\n层次遍历的结果:");
32 levelOrder(tree[0]);
33 System.out.println("\n二叉树的深度为:");
34 System.out.println(getTreeDepth(tree[0]));
35 int[] pre = {0,1,3,4,2,5,6};
36 int[] in= {3,1,4,0,5,2,6};
37 int[] after = {3,4,1,5,6,2,0};
38 Main main = new Main();
39 TreeNode root1 = main.getTreeByPreAndInfix(pre,in);
40 System.out.println("重建后的树的中序遍历为:");
41 infixOrder(root1);
42 TreeNode root2 = main.getTreeByAfterAndInfix(after,in);
43 System.out.println("\n重建后的树的中序遍历为:");
44 infixOrder(root2);
45
46 }
47
48 /**
49 * 递归实现打印二叉树的前序遍历结果
50 * @param root 二叉树的根节点
51 */
52 public static void preOrder(TreeNode root){
53 if(root==null){
54 return;
55 }
56 System.out.print(root.val+" ");
57 TreeNode left = root.left;
58 TreeNode right = root.right;
59 if(left != null){
60 preOrder(left);
61 }
62 if(right != null){
63 preOrder(right);
64 }
65 }
66
67 /**
68 * 递归实现打印二叉树的中序遍历结果
69 * @param root 二叉树的根节点
70 */
71 public static void infixOrder(TreeNode root){
72 if(root==null){
73 return;
74 }
75 TreeNode left = root.left;
76 TreeNode right = root.right;
77 if(left != null){
78 infixOrder(left);
79 }
80 System.out.print(root.val+" ");
81 if(right != null){
82 infixOrder(right);
83 }
84 }
85
86 /**
87 * 递归实现打印二叉树的后序遍历
88 * @param root 二叉树的根节点
89 */
90 public static void afterOrder(TreeNode root){
91 if(root==null){
92 return;
93 }
94 TreeNode left = root.left;
95 TreeNode right = root.right;
96 if(left != null){
97 afterOrder(left);
98 }
99 if(right != null){
100 afterOrder(right);
101 }
102 System.out.print(root.val+" ");
103 }
104
105 /**
106 * 层次遍历一个二叉树
107 * @param root 二叉树的根节点
108 */
109 public static void levelOrder(TreeNode root){
110 if(root==null){
111 return;
112 }
113 LinkedList<TreeNode> list = new LinkedList<>();
114 list.add(root);
115 TreeNode temp;
116 while (!list.isEmpty()){
117 temp = list.poll();
118 System.out.print(temp.val+" ");
119 if(temp.left!=null){
120 list.add(temp.left);
121 }
122 if(temp.right!=null){
123 list.add(temp.right);
124 }
125 }
126
127 }
128
129 HashMap<Integer,Integer> map = new HashMap<>();
130 int[] pre;
131 /**
132 * 通过前序遍历和中序遍历确定一棵二叉树
133 * @param pre 前序遍历结果数组
134 * @param infix 中序遍历结果数组
135 */
136 public TreeNode getTreeByPreAndInfix(int[] pre, int[] infix){
137 this.pre = pre;
138 for (int i = 0; i < pre.length; i++) {
139 map.put(infix[i],i);
140 }
141 return recur(0,0,infix.length-1);
142 }
143
144 /**
145 * 前序和中序递归算法,思路是在中序遍历中确定左子树和右子树,同时确定左子树和右子树的根节点
146 * 根节点肯定是在前序遍历中找,但是找根节点需要确定左右子树的长度
147 * 左子树的根节点等于当前根节点+1
148 * 右子树的根节点等于当前根节点+左子树的长度+1
149 * 要确定长度,就要在中序遍历中找到上一个根节点的位置和树的左边界和右边界
150 * @param pre_root 前序遍历中根节点在数组中你的索引值
151 * @param in_left 当前树中序遍历中的左边界
152 * @param in_right 当前树中序遍历的有边界
153 * @return 根节点
154 */
155 TreeNode recur(int pre_root,int in_left,int in_right){
156 //如果这颗树的左边界大于右边界,证明上一个节点是叶子节点,直接返回空
157 if(in_left>in_right){
158 return null;
159 }
160 //上一个节点不是叶子节点,则创建子树的根节点
161 TreeNode root = new TreeNode(pre[pre_root]);
162 //获得这个根节点在前序遍历中的下标
163 int i = map.get(pre[pre_root]);
164 //递归左子树,左子树的左边界和上一个节点的左边界一致,右边界为根节点在中序遍历中的下标减一
165 root.left = recur(pre_root+1,in_left,i-1);
166 //递归右子树,右子树的根节点在前序遍历中的下标为前一个根节点+左子树的长度(right-left)+1
167 root.right = recur(pre_root+(i-in_left)+1,i+1,in_right);
168 return root;
169 }
170
171
172 HashMap<Integer,Integer> map2 = new HashMap<>();
173 int[] after;
174
175 /**
176 * 通过后序遍历和中序遍历确定一棵二叉树
177 * @param after 后序遍历结果数组
178 * @param infix 中序遍历结果数组
179 */
180 public TreeNode getTreeByAfterAndInfix(int[] after,int[] infix){
181 this.after = after;
182 for (int i = 0; i < infix.length; i++) {
183 map2.put(infix[i],i);
184 }
185 return recur2(after.length-1,0,after.length-1);
186 }
187
188 /**
189 * 在中序遍历中确定每一棵子树的根节点
190 * @param after_root 在后序遍历中根节点的下标
191 * @param in_left 在中序遍历中当前树的左边界
192 * @param in_right 在中序遍历中当前树的有边界
193 * @return 当前树的根节点
194 */
195 TreeNode recur2(int after_root,int in_left,int in_right){
196 //这棵子树的左边界大于有边界,证明这颗子树是叶子节点
197 if(in_left>in_right){
198 return null;
199 }
200 //不是叶子节点,创建这颗子树的根节点
201 TreeNode root = new TreeNode(after[after_root]);
202 //获得当前根节点在中序遍历中的下标
203 int i = map2.get(after[after_root]);
204 //递归右子树,右子树的左边界在中序遍历中的下标是上一个根节点下标加一,右边界不变
205 root.right = recur2(after_root-1,i+1,in_right);
206 //递归左子树,左子树的根节点在后序遍历的位置=上一个的下标-右子树的长度-1,左边界不变,右边界等于上一个节点的下标-1
207 root.left = recur2(after_root-(in_right-i)-1,in_left,i-1);
208 return root;
209 }
210
211 /**
212 * 获得二叉树的深度
213 * @param root 二叉树的根节点
214 * @return 二叉树深度
215 */
216 public static int getTreeDepth(TreeNode root){
217 if(root ==null){
218 return 0;
219 }
220 int left = getTreeDepth(root.left);
221 int right = getTreeDepth(root.right);
222 if(left>right){
223 return left+1;
224 }else {
225 return right+1;
226 }
227 }
228 }
229
230 class TreeNode{
231 public int val;
232 public TreeNode left;
233 public TreeNode right;
234
235 public TreeNode(int val) {
236 this.val = val;
237 }
238 }