二叉树的遍历

67 阅读3分钟

开始简答复习一下二叉树🙌

首先一定要学会手写二叉树:

 public class TreeNode {
     int val;
     TreeNode left;
     TreeNode right;
 ​
     TreeNode() {}
     TreeNode(int val) { this.val = val; }
     TreeNode(int val, TreeNode left, TreeNode right) {
         this.val = val;
         this.left = left;
         this.right = right;
     }
 }

三种遍历方式

递归遍历

一看就会,一写就废😭

思路:递归就是自己调用自己,首先定义结果数组,然后单独写一个方法来处理

 // 前序遍历·递归·LC144_二叉树的前序遍历
 class Solution {
     public List<Integer> preorderTraversal(TreeNode root) {
         List<Integer> result = new ArrayList<Integer>();
         preorder(root, result);
         return result;
     }
 ​
     public void preorder(TreeNode root, List<Integer> result) {
         if (root == null) {
             return;
         }
         result.add(root.val);
         preorder(root.left, result);
         preorder(root.right, result);
     }
 }

迭代遍历

迭代就是非递归的方式,我们知道递归是自己调用自己,其中底层也是借助了栈这种数据结构,那我们使用迭代方式就是显示的去使用栈

前序遍历:

 // 前序遍历顺序:中-左-右,入栈顺序:中-右-左
 class Solution {
     public List<Integer> preorderTraversal(TreeNode root) {
         List<Integer> result = new ArrayList<>();
         if (root == null){
             return result;
         }
         //借助栈的数据结构来进行处理
         Stack<TreeNode> stack = new Stack<>();
         stack.push(root);
         while (!stack.isEmpty()){
             TreeNode node = stack.pop();
             result.add(node.val);
             if (node.right != null){
                 stack.push(node.right);
             }
             if (node.left != null){
                 stack.push(node.left);
             }
         }
         return result;
     }
 }

中序遍历:和前序遍历逻辑有差异,因为前序遍历要访问的元素和要处理的元素顺序是一致的,都是中间节点。

中序遍历要一直先访问左边的节点,所以借助一个指针来寻找最左边的节点

看一下中序遍历:

 // 中序遍历顺序: 左-中-右 入栈顺序: 左-右
 class Solution {
     public List<Integer> inorderTraversal(TreeNode root) {
         List<Integer> result = new ArrayList<>();
         if (root == null){
             return result;
         }
         Stack<TreeNode> stack = new Stack<>();
         //借助一个指针来寻找最左边的节点,然后这个指针作为处理顺序
         TreeNode cur = root;
         while (cur != null || !stack.isEmpty()){
            if (cur != null){
                stack.push(cur);
                cur = cur.left;
            }else{
                cur = stack.pop();
                result.add(cur.val);
                cur = cur.right;
            }
         }
         return result;
     }
 }

后序遍历:

来看后序遍历,先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了

很好理解:

 // 后序遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果
 class Solution {
     public List<Integer> postorderTraversal(TreeNode root) {
         List<Integer> result = new ArrayList<>();
         if (root == null){
             return result;
         }
         Stack<TreeNode> stack = new Stack<>();
         stack.push(root);
         while (!stack.isEmpty()){
             TreeNode node = stack.pop();
             result.add(node.val);
             if (node.left != null){
                 stack.push(node.left);
             }
             if (node.right != null){
                 stack.push(node.right);
             }
         }
         Collections.reverse(result);
         return result;
     }
 }

层序遍历

这种层序遍历方式就是图论中的广度优先遍历,同样也可以使用递归和非递归的方式来处理: 递归实现:

废话少说,先写出模版:

 // 102.二叉树的层序遍历
 class Solution {
     public List<List<Integer>> resList = new ArrayList<List<Integer>>();
 ​
     public List<List<Integer>> levelOrder(TreeNode root) {
         //checkFun01(root,0);
         checkFun02(root);
 ​
         return resList;
     }
 }

递归实现:

     //DFS--递归方式
     public void checkFun01(TreeNode node, Integer deep) {
         if (node == null) return;
         deep++;
 ​
         if (resList.size() < deep) {
             //当层级增加时,list的Item也增加,利用list的索引值进行层级界定
             List<Integer> item = new ArrayList<Integer>();
             resList.add(item);
         }
         resList.get(deep - 1).add(node.val);
 ​
         checkFun01(node.left, deep);
         checkFun01(node.right, deep);
     }

迭代实现:借助队列

     //BFS--迭代方式--借助队列
     public void checkFun02(TreeNode node) {
         if (node == null) return;
         //使用LinkedList作为队列来辅助遍历
         Queue<TreeNode> que = new LinkedList<TreeNode>();
         que.offer(node);
 ​
         while (!que.isEmpty()) {
             List<Integer> itemList = new ArrayList<Integer>();
             int len = que.size();
 ​
             while (len > 0) {
                 TreeNode tmpNode = que.poll();
                 itemList.add(tmpNode.val);
 ​
                 if (tmpNode.left != null) que.offer(tmpNode.left);
                 if (tmpNode.right != null) que.offer(tmpNode.right);
                 len--;
             }
 ​
             resList.add(itemList);
         }
 ​
     }