剑指offer | 面试题32:从上到下打印二叉树

转载本文章请标明作者和出处
本文出自《Darwin的程序空间》
本文题目和部分解题思路来源自《剑指offer》第二版

在这里插入图片描述

开始行动,你已经成功一半了,献给正在奋斗的我们

题目

本题目经过拓展一共分三道;
剑指offer | 面试题32:从上到下打印二叉树_第1张图片
(图一)

  • 题目一 | 不分行从上到下打印二叉树
    从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。如图一,则依次打印:
    3,9,20,15,7

  • 题目二 | 分行从上到下打印二叉树
    从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印一行。图一打印出来的效果为:
    3
    9,20
    15,7

  • 题目三 | 之字形打印二叉树
    请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。如图一,打印结果为:
    3
    20,9
    15,7

二叉树定义如下

public class TreeNode {

    public int val;

    public TreeNode left;

    public TreeNode right;

    public TreeNode(int x) {
        val = x;
    }
}

解题分析

二叉树的打印分很多种,递归遍历就分前中后序遍历三种方式,这三道题都属于顺序打印的方式;

首先我们应该明确二叉树这种数据结构,父节点可以找到左右两个子节点,子节点是不能找到父节点(没有持有引用);

  • 题目一
    对于题目一而言,我们始终都是从左至右打印输出,也就是先遍历到的先打印,很容易想到队列这种数据结构;我们可以定义一个队列,先把根节点放进去(这里要注意根节点的判空,也就是代码的健壮性要好,面试的时候尤其要注意这些细节),这时队列里面就有一个元素了,我们再用一个循环(条件就是这个队列不为空);每循环一次我们就取出一个节点,输出它,并且判断它的左右节点各自是否为空(因为题目要求从左到右,所以我们先判左子节点再判右子节点),不为空的话,放入队列中,这样等队列为空,跳出循环,就表示,二叉树已经遍历完成了。

  • 题目二
    题目二,相较于题目一而言,唯一多的就是换行,以题一的方式,是不能知道队列中的节点哪一个是哪一行的,有的同学会说,第一行一个、第二行两个、第三行四个…,你说的是完全二叉树是可以的,但是题目并没有说,所以这样是行不通的,《剑指offer》作者给出的解法是定义两个变量,但是这里笔者的方法是定义两个队列,第一个队列装第一行,然后把它存在的左右子节点放到第二个队列中,然后再把第二个队列中的节点存在的左右子节点放到第一个队列中,这样我们每遍历完一个队列一换行就好了。整个过程的结束条件就是两个队列都为空了,就结束了。

    可能有小伙伴说,人家只定义了两个变量,你多定义了一个队列,其实,我两个队列装的值和他一个队列里面装的一样多,元素还是那么多元素,只是我用了两个杯子而已。

    这里使用的队列是LinkedList,没错,LinkedList就是一个队列。

  • 题目三
    题目三,之字形打印。这道题分析到最后,其实就是一个逻辑,同一行先遍历的节点,它的子节点要在下一行打印的时候最后打印,如果说题目一、题目二是节点先进先出的话,那么这个就需要子节点先进后出了,那么解题所用的容器就出来了,就是栈。

    那我们试试一个栈能不能解决问题,如果这行有多个元素,你打印完第一个,就把第一个元素的子节点压到栈里面了,那么这行的第二个元素你怎么打印?所以解决问题的方案就是两个栈。

    我们定义两个栈,定义为栈1和栈2,我们先把根元素放到栈1里面,然后遍历栈1里面的节点,在把栈1的节点放入栈2,等栈1空了,在用这种方式去遍历栈2,依次类推,即可打印这个二叉树,至于之字形,读者可以自己画一下图,栈1要先放左子节点再放右子节点(以为第偶数行行要从右向左),栈2则刚好相反。总之、牢记,栈这种数据结构就是先进后出的。

代码(JAVA实现)

ps:这里笔者使用的jdk为1.8版本

  • 题目一
    public static void print1(TreeNode head) {
        if (Objects.isNull(head)) {
            return;
        }
        Deque<TreeNode> deque = new LinkedList<>();
        deque.add(head);
        while (!deque.isEmpty()) {
            TreeNode treeNode = deque.removeFirst();
            System.out.println(treeNode.val);
            if (!Objects.isNull(treeNode.left)) {
                deque.addLast(treeNode.left);
            }
            if (!Objects.isNull(treeNode.right)) {
                deque.addLast(treeNode.right);
            }
        }
    }
  • 题目二
public static void print2(TreeNode head) {
        if (Objects.isNull(head)) {
            return;
        }
        Deque<TreeNode> deque1 = new LinkedList<>();
        Deque<TreeNode> deque2 = new LinkedList<>();
        deque1.add(head);
        while (!deque1.isEmpty() || !deque2.isEmpty()) {
            if (deque2.isEmpty()) {
                while (!deque1.isEmpty()) {
                    TreeNode treeNode = deque1.removeFirst();
                    System.out.print(treeNode.val);
                    if (!Objects.isNull(treeNode.left)) {
                        deque2.addLast(treeNode.left);
                    }
                    if (!Objects.isNull(treeNode.right)) {
                        deque2.addLast(treeNode.right);
                    }
                }
            } else if (deque1.isEmpty()) {
                while (!deque2.isEmpty()) {
                    TreeNode treeNode = deque2.removeFirst();
                    System.out.print(treeNode.val);
                    if (!Objects.isNull(treeNode.left)) {
                        deque1.addLast(treeNode.left);
                    }
                    if (!Objects.isNull(treeNode.right)) {
                        deque1.addLast(treeNode.right);
                    }
                }
            }
            System.out.println();
        }
    }
  • 题目三
public static void print3(TreeNode head) {
        if (Objects.isNull(head)) {
            return;
        }
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();
        stack1.push(head);
        while (!stack1.empty() || !stack2.empty()) {
            if (stack2.empty()) {
                while (!stack1.empty()) {
                    TreeNode pop = stack1.pop();
                    System.out.print(pop.val);
                    if (!Objects.isNull(pop.left)) {
                        stack2.push(pop.left);
                    }
                    if (!Objects.isNull(pop.right)) {
                        stack2.push(pop.right);
                    }
                }
            } else if (stack1.empty()) {
                while (!stack2.empty()) {
                    TreeNode pop = stack2.pop();
                    System.out.print(pop.val);
                    if (!Objects.isNull(pop.right)) {
                        stack1.push(pop.right);
                    }
                    if (!Objects.isNull(pop.left)) {
                        stack1.push(pop.left);
                    }
                }
            }
            System.out.println();
        }
    }

各位读者如过发现代码中有什么不对或者可以优化的地方可以给我留言,我一定虚心接受。

喜欢的朋友可以加我的个人微信,我们一起进步

你可能感兴趣的:(剑指offer,算法)