• 剑指Offer对答如流系列


    面试题32:从上往下打印二叉树

    题目描述

    树的结构定义如下:

    public class Node{
            int e;
            Node left;
            Node right;
            Node(int x) { e = x; }
        }
    

    (一)不分行从上到下打印二叉树

    从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。

    比如下面二叉树,输出顺序为 8 6 10 5 7 9 11
    在这里插入图片描述

    (二)分行从上到下打印二叉树

    从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行。

    比如下面二叉树,输出顺序为

    8

    6 10

    5 7 9 11

    在这里插入图片描述

    (三)之字形打印二叉树

    请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

    比如下面二叉树,输出顺序为

    8

    10 6

    5 7 9 11

    在这里插入图片描述

    二、问题分析

    三个问题循序渐进。

    我们首先看第一个,这个很明显就是层序遍历,结点满足先进先出的原则,采用队列。每从队列中取出头部结点并打印,若其有子结点,把子结点放入队列尾部,直到所有结点打印完毕。

    关于树的层序遍历我们早就探讨过了 剑指Offer对答如流系列 - 重建二叉树

    第二个问题的解决很明显建立在第一个问题的解决方法基础上,因为要按行打印,依据树的特点,我们需要增加两个变量:当前层结点数目pCount,下一层结点数目nextCount。根据当前层结点数目来打印当前层结点,同时计算下一层结点数目,之后令pCount等于nextCount,重复循环,直到打印完毕。

    第三个问题的解决很明显建立在第二个问题的解决方法基础上,因为涉及到逆序输出,我们可以用两个栈。对于不同层的结点,一个栈用于正向存储,一个栈用于逆向存储,打印出来就正好是相反方向。

    除了这种思路之外,我们也可以多定义一个表示当前层数的变量level。每层结点不直接打印,放入一个数组中,根据此时的层数level的奇偶来决定正向还是反向打印数组。

    三、问题解答

    (1)不分行从上到下打印二叉树

    因为链表删除和添加元素 速度非常快,选择使用链表实现栈。

     public void printTree(Node root) {
            if (root == null) {
                return;
            }
            LinkedList<Node> queue = new LinkedList<>();
            queue.offer(root);
            Node node;
            while (queue.size()!=0) {
                node = queue.poll();
                System.out.print(node.e + " ");
                if (node.left != null)
                    queue.offer(node.left);
                if (node.right != null)
                    queue.offer(node.right);
            }
            System.out.println();
        }
    

    (2)分行从上到下打印二叉树

    	public void printTree(Node root) {
            if (root == null) {
                return;
            }
            LinkedList<Node> queue = new LinkedList<>();
            queue.offer(root);
            Node node = null;
            int pCount;      //当前层结点数目
            int nextCount = 1;   //下一层结点数目
            while (!queue.isEmpty()) {
                pCount = nextCount;
                nextCount = 0;
                //打印当前层数字,并计算下一层结点数目
                for (int i = 1; i <= pCount; i++) {
                    node = queue.poll();
                    System.out.print(node.e + " ");
                    if (node.left != null) {
                        queue.offer(node.left);
                        nextCount++;
                    }
                    if (node.right != null) {
                        queue.offer(node.right);
                        nextCount++;
                    }
                }
                System.out.println();
            }
        }
    

    (3)之字形打印二叉树

    思路1

      public void printTree(Node root) {
            if (root == null) {
                return;
            }
            
            Stack<Node> stack1 = new Stack<>();
            Stack<Node> stack2 = new Stack<>();
            Node node;
            stack1.push(root);
            while(!stack1.empty() || !stack2.empty()) {
                while(!stack1.empty()) {
                    node=stack1.pop();
                    System.out.print(node.e + " ");
                    if (node.left != null)
                        stack2.push(node.left);
                    if (node.right != null)
                        stack2.push(node.right);
                }
                System.out.println();
                while(!stack2.empty()) {
                    node=stack2.pop();
                    System.out.print(node.e + " ");
                    if (node.right != null)
                        stack1.push(node.right);
                    if (node.left != null)
                        stack1.push(node.left);
                }
                System.out.println();
            }
        }
    

    思路2

      public void printTree(Node root) {
            if (root == null) {
                return;
            }
    
            LinkedList<Node> queue = new LinkedList<>();
            queue.offer(root);
            Node node;
            int pCount;      //当前层结点数目
            int nextCount = 1;   //下一层结点数目
            int level=1;    //层数
            int[] pNums;    //用于存储当前层的数字
            while (!queue.isEmpty()) {
                pCount = nextCount;
                nextCount = 0;
                pNums=new int[pCount];
                //存储当前层数字,并计算下一层结点数目
                for (int i = 0; i < pCount; i++) {
                    node = queue.poll();
                    pNums[i]=node.e;
                    if (node.left != null) {
                        queue.offer(node.left);
                        nextCount++;
                    }
                    if (node.right != null) {
                        queue.offer(node.right);
                        nextCount++;
                    }
                }
                //根据当前层数确定正向或者反向打印数组
                if( (level&1) != 0 ) {
                    for(int i=0; i<pCount; i++) {
                        System.out.print(pNums[i]+" ");
                    }
                } else {
                    for(int i=pCount-1; i>=0; i--) {
                        System.out.print(pNums[i]+" ");
                    }
                }
                level++;
                System.out.println();
            }
        }
    
  • 相关阅读:
    将eclipse的编码设置成UTF-8
    git提交代码时报rejected
    Vue.js
    快速计算进制之间的转换
    android中canvas.drawText参数的介绍以及绘制一个文本居中的案例
    progressbar原始效果
    面试问题总结
    Android Material Design学习日志
    Android进阶之解决RecyclerView notifyItem闪屏问题
    Android TextView行间距解析
  • 原文地址:https://www.cnblogs.com/JefferyChenXiao/p/12246400.html
Copyright © 2020-2023  润新知