前序遍历、中序遍历、后续遍历图解以及算法

概述:

本文包含以下算法,大部分以递归实现

前序遍历(中左右):先输出自己,然后是左孩子,最后右孩子;

中序遍历(左中右):先输出左孩子,然后是自己,最后右孩子;

后序遍历(左右中):先输出左孩子,然后是右孩子,最后自己;

层次遍历 :一层一层从上到下从左到右遍历;

前序遍历和中序遍历确定一棵二叉树;

后序遍历和中序遍历确定一棵二叉树;

前序遍历和后续遍历其中一种加上中序遍历,便可以确定一颗二叉树;

以下是关于遍历的算法

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 }