【数据结构】二叉树 | 层序遍历

117 阅读4分钟

题目102. 二叉树的层序遍历 - 力扣(LeetCode)

二叉树的层序遍历:逐层,从左到右的访问所有节点

image.png

思路

用队列来存储节点,先进先出;用int size = 1记录每一层的元素个数,逐层遍历后清零

  1. 根节点入队,offer(root)
  2. 外层循环!queue.isEmpty()控制遍历所有节点,更新当前size,初始化每层结果为空数组
  3. 内层循环size--控制遍历每层节点,每个节点处理逻辑:poll(node),若node.left非空,则offer(node.left)若node.left非空,则offer(node.left)
  4. 内层循环结束后,更新结果数组result

代码

下一次内层循环开始前,需要更新当前层元素个数size,具体代码实现有很多种方法
第一种: 在内层循环开始前,更新size = queue.size()
第二种: 在内层循环里计数cnt,内层循环结束后,size = cnt

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root == null) {
            return res;
        }
        queue.offer(root);
        int size = 1;
        
        while(!queue.isEmpty()) {
            List<Integer> a = new ArrayList<>();
            size = queue.size();
            // int cnt = 0;
            for(;size > 0;size--){
                TreeNode node = queue.poll();
                a.add(node.val);
                if(node.left != null) {
                    queue.offer(node.left);
                    // cnt++;
                }
                if(node.right != null) {
                    queue.offer(node.right);
                    // cnt++;
                }
            }
            res.add(a);
        }
        return res;
    }
    
}

总结:

层序遍历的定义不难理解,需要利用队列的先进先出特性,来保存每层节点,配合size内层循环,实现每层节点的记录

学习时长:50min

补充题

429. N 叉树的层序遍历 - 力扣(LeetCode)

中等-学习时间30min

思路

层序遍历同样的思路,两层循环

  • 外层循环控制队列所有节点的遍历
  • 内层循环控制每一层节点遍历
  • 这道题比较绕的是子节点是一个List集合,利用增强for循环,需要初始化for(Node i : nodelist)

代码

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
    public List<List<Integer>> levelOrder(Node root) {
        Queue<Node> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root == null) return res;
        queue.offer(root);
        int size = 1;
        while(!queue.isEmpty()) {
            List<Integer> a = new ArrayList<>();
            size = queue.size();
            for(;size > 0;size--) {
                Node node = queue.poll();
                a.add(node.val);
                List<Node> nodelist = node.children;
                for(Node i : nodelist) {
                    if(i != null) {
                        queue.offer(i);
                    }
                }
            }
            // a.add(null);
            res.add(a);
        }
        return res;
    }
}

107. 二叉树的层序遍历 II - 力扣(LeetCode)

自下而上遍历每一层
中等-学习时间40min

思路

层序遍历同样的思路,两层循环

  • 外层循环控制队列所有节点的遍历
  • 内层循环控制每一层节点遍历
  • 这道题需要自下而上遍历,得到结果后反转,这似乎没有难度,但是增加了空间复杂度
    解决办法:利用java的链表数据结构ArrayList,在头部插入元素的时间复杂度是O(1)

代码

ArrayList在头部插入元素res.add(0,level)

class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root == null) return res;
        int size = 1;
        queue.offer(root);

        while(!queue.isEmpty()) {
            List<Integer> level = new ArrayList<>();
            size = queue.size();
            for(;size > 0;size--) {
                TreeNode node = queue.poll();
                level.add(node.val);
                if(node.left != null) {
                    queue.offer(node.left);
                }
                if(node.right != null) {
                    queue.offer(node.right);
                }
            }
            res.add(0,level);
        }

        return res;

    }
}

199. 二叉树的右视图 - 力扣(LeetCode)

中等-学习时间6min

思路

层序遍历同样的思路,两层循环

  • 外层循环控制队列所有节点的遍历
  • 内层循环控制每一层节点遍历
  • 这道题需要记录每一层的最后一个元素

代码

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<Integer> result = new ArrayList<>();
        if(root == null) return result;
        int size = 1;
        queue.offer(root);
        while(!queue.isEmpty()) {
            size = queue.size();
            for(;size > 0;size--) {
                TreeNode node = queue.poll();
                if(node.left != null) {
                    queue.offer(node.left);
                }
                if(node.right != null) {
                    queue.offer(node.right);
                }
                if(size == 1) {
                    result.add(node.val);
                }
            }
        }
        return result;
    }
}

637. 二叉树的层平均值 - 力扣(LeetCode)

简单-学习时间20min

思路

层序遍历同样的思路,两层循环

  • 外层循环控制队列所有节点的遍历
  • 内层循环控制每一层节点遍历
  • 这道题需要记录每一层的平均值

代码

  • double sum = 0;如果用int,如果和超过整型最大值2147483647,导致测试样例不过
  • 这里用cnt来存储size的值,其实可以用i作为内层循环变量for(int i = 0;i<size;i++),同样可以遍历内层循环的所有元素,同时不需要用cnt来存储size值,避免意义重复。
class Solution {
    public List<Double> averageOfLevels(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<Double> result = new ArrayList<>();
        if(root == null) return result;
        int size = 1;
        queue.offer(root);
        while(!queue.isEmpty()) {
            size = queue.size();
            int cnt = size;
            double sum = 0;
            for(;size > 0;size--) {
                TreeNode node = queue.poll();
                sum += node.val;
                if(node.left != null) {
                    queue.offer(node.left);
                }
                if(node.right != null) {
                    queue.offer(node.right);
                }
            }
            result.add(sum/cnt);
        }
        return result;
    }
}

补充知识点

类型转换

  1. 自动类型转换:也叫隐式转换

转换的条件:若不同数据类型可以兼容,而且目标值的数据类型范围大于操作数的数据类型-->可以发生转换
转换的场景:在运算中,所有的数都要转化成同一种数据类型,此时会发生自动类型转换,将低级类型数据向高级类型数据转换。

  • 数字:byte-->short-->int-->long-->float-->double
  • 字符:char-->int
  • 特殊:char(-->int-->long-->float)-->double

上面代码中sum/cnt,sum是double类型,cnt是int类型,那么结果是什么类型?
答:double类型

  1. 强制类型转换:也叫显式转化

转换的条件:若不同数据类型可以兼容,但目标值范围更小
转换的场景:程序中虽然出现double类型,但是结果希望以int类型存储;可能导致精度丢失