算法打卡Day13(补卡)| 二叉树篇-递归遍历、迭代遍历、层序遍历

67 阅读3分钟

1. 二叉树的结构定义

  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;
      }
  }

2. 递归遍历

题目链接:

2.1 递归三要素

  1. 确定递归函数的参数和返回值
  2. 确定终止条件
  3. 确定单层递归的逻辑

2.2 代码

前序:中左右 中序:左中右 后序:左右中

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        front(root, list);
        return list;
    }
​
    public void front(TreeNode cur, List<Integer> list){
        if(cur==null) return;
        //中左右
        list.add(cur.val);
        front(cur.left, list);
        front(cur.right, list);
    }
}

3. 迭代遍历

递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中

所以迭代遍历使用栈去实现

3.1 前序遍历

使用栈实现前序遍历,即中左右,放置顺序为中右左,只有这样从栈里取出的元素顺序符合要求

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        if(root==null) return list;
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            list.add(node.val);
            if(node.right!=null) {
                stack.add(node.right);
            } 
            if(node.left!=null){
                stack.add(node.left);
            } 
        }
        return list;
    }
}

3.2 后序遍历

有点抽象

3.3 中序遍历

访问的顺序和要处理(放入到list中)的顺序不一致

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        //访问顺序和处理顺序不一致
        //使用一个指针去后序遍历,将需要处理的先放在栈中
        Stack<TreeNode> stack = new Stack<>();
        List<Integer> list = new ArrayList<>();
        TreeNode cur = root;
        while(cur!=null || !stack.isEmpty()){
            if(cur!=null){
                stack.add(cur);
                cur = cur.left;
            }else{
                cur = stack.pop();
                list.add(cur.val);
                cur = cur.right;
            }
        }
        return list;
    }
}

4. 层序遍历

使用队列,将每层元素放置进去,每次弹出元素时,将该元素的左右节点放置进队列,最后使用二维数组将其存起来

102. 二叉树的层序遍历

题目链接:leetcode.cn/problems/bi…

关键点:用队列实现。队列先进先出,层序遍历也属于先遍历到的先取

lass Solution {
​
    public List<List<Integer>> levelOrder(TreeNode root) {
        return checkFunc(root);
    }
​
    public List<List<Integer>> checkFunc(TreeNode root){
                List<List<Integer>> resultList = new ArrayList<>();
        //顶点额外处理
        if(root==null) return resultList;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            List<Integer> itemList = new ArrayList<>();
            int size = queue.size();
            while(size>0){
                TreeNode node = queue.poll();
                itemList.add(node.val);
                //⏰第一次写不仔细 将node写成了root,一直超过时间限制
                if(node.left!=null) queue.add(node.left);
                if(node.right!=null) queue.add(node.right);
                size--;
            } 
            resultList.add(itemList);       
        }
        return resultList;
    }
}

107. 二叉树的层次遍历 II

题目链接:leetcode.cn/problems/bi…

关键点:自底向上遍历,将自顶向下的结果反转(for循环从后至前)即可

109. 二叉树的右视图

题目链接:leetcode.cn/problems/bi…

  • 递归法
class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        return right(root, list);
    }
​
    private List<Integer> right(TreeNode root, List<Integer> list){
        if(root==null) return list;
        list.add(root.val);
        return right(root.right, list);
    }
}
  • 层序遍历法
class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        //使用层序遍历:队列 每层每层放进去 ,除了每层最后一个,其他元素全部poll()
        Queue<TreeNode> queue = new LinkedList<>();
        List<Integer> list = new ArrayList<>();
        if(root==null) return list;
        queue.add(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            for(int i=0; i<size; i++){
                TreeNode node = queue.poll();
                if(node.left!=null){
                    queue.add(node.left);
                }
                if(node.right!=null){
                    queue.add(node.right);
                }
                if(i==size-1){
                    list.add(node.val);
                }
            }
        }
        return list;
    }
}

637. 二叉树的层平均值

题目链接:leetcode.cn/problems/av…

class Solution {
    public List<Double> averageOfLevels(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<Double> list = new ArrayList<>();
        if(root==null) return list;
        queue.add(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            Double sum = 0.0;
            for(int i=0; i<size; i++){
                TreeNode node = queue.poll();
                if(node.left!=null){
                    queue.add(node.left);
                }
                if(node.right!=null){
                    queue.add(node.right);
                }
                sum += node.val;
            }
            list.add(sum/size);
        }
        return list;
    }
}

5. 总结

  • 深度遍历:用先进后出的栈实现
  • 层序遍历:用先进先出的队列实现
  • 递归法
  • 迭代法(非递归方式)