剑指 Offer 32 - I、II、III. 从上到下打印二叉树

在这里插入图片描述

题目一 不分行从上到下打印二叉树

队列 BFS

 使用广度优先可以遍历一幅有向图,树是图的一种特殊退化形式,从上到下按层遍历二叉树,从本质上来说就是广度优先遍历二叉树。
 实现BFS可以使用一个队列,每次从队列中取出一个节点,将其子节点加入到队列中,知道队列为空。
 由于题目要求输出一个数组,所以需要先知道树的节点数,因此可以使用递归先得到树的大小。
 另一种方案是使用java提供的ArrayList, 最后将ArrayList的元素赋值给数组。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] levelOrder(TreeNode root) {
        if(root == null) return new int[]{};
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int n = nodeNums(root);
        int[] ans = new int[n];
        int index = 0;
        // System.out.println(n);
        while(!queue.isEmpty()){
            TreeNode cur = queue.poll();
            ans[index++] = cur.val;
            if(cur.left != null) queue.offer(cur.left);
            if(cur.right != null) queue.offer(cur.right);
        }
        return ans;
    }

    private int N = 0;

    private int nodeNums(TreeNode node){
        if(node.left == null && node.right == null){
            return ++N;
        }else{
            ++N;
        }
        if(node.left != null)
            nodeNums(node.left);
        if(node.right != null)
            nodeNums(node.right);
        return  N;
    }
}

题目二 分行从上到下打印二叉树

在这里插入图片描述

解法一

这题与第一题的不同在于要分行打印。第一种思路是从队列中每次取出当前层的所有元素加入list中,同时在队列中加入下一层所有元素,也就是取一层加下一层,知道最后队列为空

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root == null) return new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        List<List<Integer>> ans = new ArrayList<>();
        while(!queue.isEmpty()){
            int floorSize = queue.size();
            List<Integer> eachFloor = new ArrayList<>();
            for(int i = 0; i < floorSize; i++){
                TreeNode cur = queue.poll();
                if(cur.left != null) queue.offer(cur.left);
                if(cur.right != null) queue.offer(cur.right);
                eachFloor.add(cur.val);
            }
            ans.add(eachFloor);
        }
        return ans;
    }
}

解法二

 第二种思路还是从队列中每次取一个节点,然后将其子节点加入队列尾部。
使用一个变量记录当前层剩余打印的节点数,使用另一个变量记录下一层的节点数。
 每次取出一个节点当前层剩余的节点减少1;取出一个节点后队列中加入其子节点,记录下一层节点数;当前层剩余节点为0时说明当前层以及取完,进入下一层。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root == null) return new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        List<List<Integer>> ans = new ArrayList<>();
         List<Integer> level = new ArrayList<>();
        int nextLevel = 0;//记录下一层的节点数
        int toBePrinted = 1;//当前层应打印的节点数
        while(!queue.isEmpty()){
            TreeNode cur = queue.poll();
            level.add(cur.val);
            toBePrinted--;
            if(cur.left != null){
                ++nextLevel;
                queue.offer(cur.left);
            }
            if(cur.right != null){
                ++nextLevel;
                queue.offer(cur.right);
            }
            if(toBePrinted == 0){
                ans.add(level);
                level = new ArrayList<Integer>();
                toBePrinted = nextLevel;
                nextLevel = 0;
            }
        }
        return ans;
    }
}

题目三 之字形打印二叉树

在这里插入图片描述

在这里插入图片描述
 以上面这颗二叉树为例,先打印节点3,然后将其子节点(9,20)保存到数据结构中。打印第二层时需要先打印20再打印9,所以是先进后出,可以使用“栈”保存(9,20)。打印第三层时从栈中先取出的是20,而打印需要先打印15,再打印7所以需要将7先压入栈,再将15压入栈。不同的层压栈顺序不一样所以需要两个栈交替使用。
 下面的解法为:

  • 定义两个栈:stack1保存“从左向右”打印的层节点,stack2保存从右向左打印的层节点
  • stack1中先压入根节点,弹出根节点后,将其子节点按顺序压入stack2
  • 从stack2中弹出所以节点并将其子节点按顺序压入stack1中
  • 以此类推知道两个栈都为空
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root == null) return new ArrayList();
        LinkedList<TreeNode> stack1 = new LinkedList<>();
        LinkedList<TreeNode> stack2 = new LinkedList<>();
        stack1.push(root);
        boolean nextDirect = true; //下一层打印的方向false:从左到右,true:从右到左
        List<List<Integer>> ans = new ArrayList<>();
        while(!stack1.isEmpty() || !stack2.isEmpty()){
            int size = nextDirect ? stack1.size() : stack2.size();
            List<Integer> level = new LinkedList<>();
            for(int i = 0; i < size; i++){
                TreeNode node = nextDirect ? stack1.pop() : stack2.pop();
                level.add(node.val);
                if(nextDirect){
                    if(node.left != null)
                        stack2.push(node.left);
                    if(node.right != null)
                        stack2.push(node.right);
                }else{
                    if(node.right != null)
                        stack1.push(node.right);
                    if(node.left != null)
                        stack1.push(node.left);
                }
            }
            ans.add(level);
            nextDirect = !nextDirect;
        }
        return ans;
    }
}

 相同的思路,一种更简洁的写法。定义一个数组存储两个栈:stack[0],stack[1];
 使用两个变量current和next来交替使用这两个栈。每次从当前栈中按每次一个取出所有元素,将这些元素根据当前打印顺序压入另一个栈中。当前栈中元素为空时,将两个栈进行交替。

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if(root == null) return new ArrayList();
        LinkedList<TreeNode>[] stack = new LinkedList[]{new LinkedList(), new LinkedList()};
        stack[0].push(root);
        int current = 0;//标记打印顺序: 0:从左向右,1:从右向左
        int next = 1;//下一层
        List<List<Integer>> ans = new ArrayList<>();
        List<Integer> level = new ArrayList<>();
        while(!stack[0].isEmpty() || !stack[1].isEmpty()){
            TreeNode node = stack[current].pop();
            level.add(node.val);
            if(current == 0){
                if(node.left != null)
                    stack[next].push(node.left);
                if(node.right != null)
                    stack[next].push(node.right);
            }else{
                if(node.right != null)
                    stack[next].push(node.right);
                if(node.left != null)
                    stack[next].push(node.left);
            }
            if(stack[current].isEmpty()){
                ans.add(level);
                level = new ArrayList<>();
                current = 1 - current;
                next = 1 - next;
            }
        }
        return ans;
    }
}
posted @ 2020-08-26 13:28  消灭猕猴桃  阅读(66)  评论(0编辑  收藏  举报