二叉树前中后层序遍历方法(Java版)
二叉树前中后层序遍历方法(Java版)
二叉树的节点如下所示:
1 public class TreeNode {
2 int val;
3 TreeNode left;
4 TreeNode right;
5 TreeNode() {}
6 TreeNode(int val) { this.val = val; }
7 TreeNode(int val, TreeNode left, TreeNode right) {
8 this.val = val;
9 this.left = left;
10 this.right = right;
11 }
12 }
1 二叉树前序遍历
前序遍历的遍历顺序是:中左右。Leetcode对应题目为144. 二叉树的前序遍历。
下图二叉树的前序遍历为:ABDGCEFH
1.1 递归
1 class Solution {
2 public List<Integer> preorderTraversal(TreeNode root) {
3 List<Integer> list = new ArrayList<>();
4 traversal(root,list);
5 return list;
6 }
7
8 void traversal(TreeNode root,List<Integer> list){
9 if(root==null) return;
10 //先访问当前节点
11 list.add(root.val);
12 //遍历左孩子
13 traversal(root.left,list);
14 //再遍历右孩子
15 traversal(root.right,list);
16 }
17 }
1.2 迭代
1 class Solution {
2 public List<Integer> preorderTraversal(TreeNode root) {
3 //保存节点值
4 List<Integer> list = new ArrayList<>();
5 //保存访问过的节点
6 Stack<TreeNode> stack = new Stack<>();
7 TreeNode p = root;
8 while(p!=null || !stack.empty()){
9 if(p!=null){
10 list.add(p.val);
11 //将当前节点入栈
12 stack.push(p);
13 //访问左孩子
14 p=p.left;
15 }else{
16 //出栈最近访问的节点,并访问其右孩子
17 p=stack.pop();
18 p=p.right;
19 }
20 }
21 return list;
22 }
23 }
2 二叉树中序遍历
中序遍历的遍历顺序是:左中右。Leetcode对应题目为94. 二叉树的中序遍历。
下图二叉树的中序遍历为:DGBAECHF
2.1 递归
1 class Solution {
2 public List<Integer> inorderTraversal(TreeNode root) {
3 List<Integer> list = new ArrayList<>();
4 traversal(root,list);
5 return list;
6 }
7
8 void traversal(TreeNode root,List<Integer> list){
9 if(root==null) return;
10 traversal(root.left,list);
11 list.add(root.val);
12 traversal(root.right,list);
13 }
14 }
2.2 迭代
1 class Solution {
2 public List<Integer> inorderTraversal(TreeNode root) {
3 List<Integer> list = new ArrayList<>();
4 Stack<TreeNode> stack = new Stack<>();
5 TreeNode p = root;
6 while(p!=null || !stack.empty()){
7 if(p!=null){
8 //先不断遍历左孩子,将左孩子入栈
9 stack.push(p);
10 p=p.left;
11 }else{
12 //左孩子为空或遍历完成后,就将父节点出栈并遍历,再访问右孩子
13 p = stack.pop();
14 list.add(p.val);
15 p=p.right;
16 }
17 }
18 return list;
19 }
20 }
3 二叉树后序遍历
后序遍历的遍历顺序是:左右中。Leetcode对应题目为145. 二叉树的后序遍历。
下图二叉树的后序遍历为:GDBEHFCA
3.1 递归
1 class Solution {
2 public List<Integer> postorderTraversal(TreeNode root) {
3 List<Integer> list = new ArrayList<>();
4 traversal(root,list);
5 return list;
6 }
7
8 void traversal(TreeNode root,List<Integer> list){
9 if(root==null) return;
10 traversal(root.left,list);
11 traversal(root.right,list);
12 list.add(root.val);
13 }
14 }
3.2 迭代
技巧法—该迭代方法,在前序遍历的迭代方法上稍作了修改。前序遍历时先访问父节点,再访问左孩子,最后访问右孩子,形成中左右的遍历顺序。在这里,先访问父节点,再访问右孩子,最后访问左孩子,形成中右左的遍历顺序。而我们知道右序遍历的遍历顺序是左右中,我们把上面得到的结果反转不就得到后序遍历的结果了。
1 class Solution {
2 public List<Integer> postorderTraversal(TreeNode root) {
3 List<Integer> list = new ArrayList<>();
4 Stack<TreeNode> stack = new Stack<>();
5 TreeNode p = root;
6 while(p!=null || !stack.empty()){
7 if(p!=null){
8 list.add(p.val);
9 stack.push(p);
10 p = p.right;
11 }else{
12 p = stack.pop();
13 p = p.left;
14 }
15 }
16 //将list中的结果反转
17 Collections.reverse(list);
18 return list;
19 }
20 }
常规法—后序遍历需要确定是从左子树回到父节点,还是从右子树回到父节点。如果从左子树回到父节点,则需要先遍历右子树;如果从右子树回到父节点,则访问父节点。在这里,用节点pre标记前一个访问的节点,用node标记当前要处理的节点,当node的右子树非空且不是前一个访问的节点(pre)时,先访问node的右子树,否则访问node节点。
1 class Solution {
2 public List<Integer> postorderTraversal(TreeNode root) {
3 List<Integer> list = new ArrayList<>();
4 Stack<TreeNode> stack = new Stack<>();
5 TreeNode pre = null;
6 while(root!=null || !stack.isEmpty()){
7 //先遍历左子树
8 while (root != null) {
9 stack.push(root);
10 root = root.left;
11 }
12 TreeNode node = stack.pop();
13 //当右子树非空,同时右子树还没访问时,先访问右子树
14 if (node.right != null && node.right != pre) {
15 root = node.right;
16 stack.push(node);
17 }else{
18 //该节点的右子树为空或已访问后,就访问该节点
19 list.add(node.val);
20 pre = node;
21 }
22 }
23 return list;
24 }
25 }
4 二叉树层序遍历
层序遍历的遍历顺序是:从左至右一层层访问。Leetcode对应题目为102. 二叉树的层序遍历。
下图二叉树的层序遍历为:ABCDEFGH
4.1 递归
1 class Solution {
2
3 List<List<Integer>> reList = new ArrayList<>();
4
5 public List<List<Integer>> levelOrder(TreeNode root) {
6 traversal(root,0);
7 return reList;
8 }
9
10 void traversal(TreeNode root,int deep){
11 if(root==null) return;
12 deep++;
13 if(reList.size()<deep){
14 //当层级增加时,list的Item也增加,利用list的索引值进行层级界定
15 List<Integer> item = new ArrayList<>();
16 reList.add(item);
17 }
18 reList.get(deep-1).add(root.val);
19 traversal(root.left,deep);
20 traversal(root.right,deep);
21 }
22 }
4.2 迭代
1 class Solution {
2 public List<List<Integer>> levelOrder(TreeNode root) {
3 List<List<Integer>> reList = new ArrayList<>();
4 if(root==null) return reList;
5 Queue<TreeNode> queue = new LinkedList<>();
6 queue.offer(root);
7 while(!queue.isEmpty()){
8 List<Integer> item = new ArrayList<>();
9 //len保存每层的节点数
10 int len = queue.size();
11 while(len>0){
12 TreeNode p = queue.poll();
13 item.add(p.val);
14 if(p.left!=null) queue.offer(p.left);
15 if(p.right!=null) queue.offer(p.right);
16 len--;
17 }
18 reList.add(item);
19 }
20 return reList;
21 }
22 }