本文参考自《剑指offer》一书,代码采用Java语言。

更多:《剑指Offer》Java实现合集  

题目 

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

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

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

思路

  (一)不分行从上往下打印二叉树:该题即为对二叉树的层序遍历,结点满足先进先出的原则,采用队列。每从队列中取出头部结点并打印,若其有子结点,把子结点放入队列尾部,直到所有结点打印完毕。

	/*
* 不分行从上往下打印二叉树
*/
// 题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。
public void printTree1(TreeNode root) {
if (root == null)
return;
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
TreeNode node = null;
while (queue.size()!=0) {
node = queue.poll();
System.out.print(node.val + " ");
if (node.left != null)
queue.offer(node.left);
if (node.right != null)
queue.offer(node.right);
}
System.out.println();
}

  (二)分行从上到下打印二叉树:同样使用队列,但比第一题增加两个变量:当前层结点数目pCount,下一层结点数目nextCount。根据当前层结点数目来打印当前层结点,同时计算下一层结点数目,之后令pCount等于nextCount,重复循环,直到打印完毕。

	/*
* 分行从上到下打印二叉树
*/
// 题目:从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层
// 打印到一行。
public void printTree2(TreeNode root) {
if (root == null)
return;
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
TreeNode node = null;
int pCount = 0; //当前层结点数目
int nextCount = 1; //下一层结点数目
while (!queue.isEmpty()) {
pCount = nextCount;
nextCount = 0;
//打印当前层数字,并计算下一层结点数目
for (int i = 1; i <= pCount; i++) {
node = queue.poll();
System.out.print(node.val + " ");
if (node.left != null) {
queue.offer(node.left);
nextCount++;
}
if (node.right != null) {
queue.offer(node.right);
nextCount++;
}
}
System.out.println();
}
}

  (三)之字形打印二叉树:

    (1)自己开始想的方法:在(二)的基础上,多定义一个表示当前层数的变量level。每层结点不直接打印,放入一个数组中,根据此时的层数level的奇偶来决定正向还是反向打印数组。

	/*
* 之字形打印二叉树
*/
// 题目:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺
// 序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,
// 其他行以此类推。
/**
* 自己开始想的方法,采用数组存储每层的数字,根据当前层数确定正反向打印数组
*/
public void printTree3_1(TreeNode root) {
if (root == null)
return;
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
TreeNode node = null;
int pCount = 0; //当前层结点数目
int nextCount = 1; //下一层结点数目
int level=1; //层数
int[] pNums=null; //用于存储当前层的数字
while (!queue.isEmpty()) {
pCount = nextCount;
nextCount = 0;
pNums=new int[pCount];
//存储当前层数字,并计算下一层结点数目
for (int i = 0; i < pCount; i++) {
node = queue.poll();
pNums[i]=node.val;
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();
}
}

    (2)书中提供的方法:采用两个栈,对于不同层的结点,一个栈用于正向存储,一个栈用于逆向存储,打印出来就正好是相反方向。

	/**
* 采用两个栈进行操作的方法
*/
public void printTree3_2(TreeNode root) {
if (root == null)
return;
Stack<TreeNode> stack1 = new Stack<TreeNode>();
Stack<TreeNode> stack2 = new Stack<TreeNode>();
TreeNode node = null;
stack1.push(root);
while(!stack1.empty() || !stack2.empty()) {
while(!stack1.empty()) {
node=stack1.pop();
System.out.print(node.val + " ");
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.val + " ");
if (node.right != null)
stack1.push(node.right);
if (node.left != null)
stack1.push(node.left);
}
System.out.println();
}
}

  

测试算例 

  1.功能测试(完全二叉树;左斜树;右斜树)

  2.特殊测试(null;一个结点)

完整Java代码

含测试代码:

import java.util.LinkedList;
import java.util.Stack;
/**
*
* @Description 面试题32:从上往下打印二叉树
*
* @author yongh
*/ public class PrintTreeFromTopToBottom {
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null; public TreeNode(int val) {
this.val = val;
}
} /*
* 不分行从上往下打印二叉树
*/
// 题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。
public void printTree1(TreeNode root) {
if (root == null)
return;
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
TreeNode node = null;
while (queue.size()!=0) {
node = queue.poll();
System.out.print(node.val + " ");
if (node.left != null)
queue.offer(node.left);
if (node.right != null)
queue.offer(node.right);
}
System.out.println();
} /*
* 分行从上到下打印二叉树
*/
// 题目:从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层
// 打印到一行。
public void printTree2(TreeNode root) {
if (root == null)
return;
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
TreeNode node = null;
int pCount = 0; //当前层结点数目
int nextCount = 1; //下一层结点数目
while (!queue.isEmpty()) {
pCount = nextCount;
nextCount = 0;
//打印当前层数字,并计算下一层结点数目
for (int i = 1; i <= pCount; i++) {
node = queue.poll();
System.out.print(node.val + " ");
if (node.left != null) {
queue.offer(node.left);
nextCount++;
}
if (node.right != null) {
queue.offer(node.right);
nextCount++;
}
}
System.out.println();
}
} /*
* 之字形打印二叉树
*/
// 题目:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺
// 序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,
// 其他行以此类推。
/**
* 自己开始想的方法,采用数组存储每层的数字,根据当前层数确定正反向打印数组
*/
public void printTree3_1(TreeNode root) {
if (root == null)
return;
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
TreeNode node = null;
int pCount = 0; //当前层结点数目
int nextCount = 1; //下一层结点数目
int level=1; //层数
int[] pNums=null; //用于存储当前层的数字
while (!queue.isEmpty()) {
pCount = nextCount;
nextCount = 0;
pNums=new int[pCount];
//存储当前层数字,并计算下一层结点数目
for (int i = 0; i < pCount; i++) {
node = queue.poll();
pNums[i]=node.val;
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();
}
} /**
* 采用两个栈进行操作的方法
*/
public void printTree3_2(TreeNode root) {
if (root == null)
return;
Stack<TreeNode> stack1 = new Stack<TreeNode>();
Stack<TreeNode> stack2 = new Stack<TreeNode>();
TreeNode node = null;
stack1.push(root);
while(!stack1.empty() || !stack2.empty()) {
while(!stack1.empty()) {
node=stack1.pop();
System.out.print(node.val + " ");
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.val + " ");
if (node.right != null)
stack1.push(node.right);
if (node.left != null)
stack1.push(node.left);
}
System.out.println();
}
} //============测试代码==============
private void test(int testNum,TreeNode root) {
System.out.println("=========test"+testNum+"===========");
System.out.println("method1:");
printTree1(root);
System.out.println("method2:");
printTree2(root);
System.out.println("method3_1:");
printTree3_1(root);
System.out.println("method3_2:");
printTree3_2(root);
} //null
private void test1() {
TreeNode node=null;
test(1, node);
} //单个结点
private void test2() {
TreeNode node=new TreeNode(1);
test(2, node);
} //左斜
private void test3() {
TreeNode node1=new TreeNode(1);
TreeNode node2=new TreeNode(2);
TreeNode node3=new TreeNode(3);
node1.left=node2;
node2.left=node3;
test(3, node1);
} //右斜
private void test4() {
TreeNode node1=new TreeNode(1);
TreeNode node2=new TreeNode(2);
TreeNode node3=new TreeNode(3);
node1.right=node2;
node2.right=node3;
test(4, node1);
} //完全二叉树
private void test5() {
TreeNode[] nodes = new TreeNode[15];
for(int i=0;i<15;i++) {
nodes[i]= new TreeNode(i+1);
}
for(int i=0;i<7;i++) {
nodes[i].left=nodes[2*i+1];
nodes[i].right=nodes[2*i+2];
}
test(5, nodes[0]);
} public static void main(String[] args) {
PrintTreeFromTopToBottom demo= new PrintTreeFromTopToBottom();
demo.test1();
demo.test2();
demo.test3();
demo.test4();
demo.test5();
}
}

  

=========test1===========
method1:
method2:
method3_1:
method3_2:
=========test2===========
method1: method2: method3_1: method3_2: =========test3===========
method1: method2: method3_1: method3_2: =========test4===========
method1: method2: method3_1: method3_2: =========test5===========
method1: method2: method3_1: method3_2:

PrintTreeFromTopToBottom

收获

  1.层序遍历时,一般都要用到队列,可以用LinkedList类(方法:poll() 和 offer(Obj) )。

  2.在分行打印时,定义的两个int有明显实际意义(当前层结点数目,下一层结点数目)。自己编程时,一开始只知道要设置两个变量,但没有去想这两个变量的实际意义。当明白变量意义时,自己的思路会更清晰,而且代码可读性也更好。

  

更多:《剑指Offer》Java实现合集  

  

【Java】 剑指offer(32) 从上往下打印二叉树的更多相关文章

  1. 剑指offer——32从上到下打印二叉树

    题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印.   题解: 就是简单的层序遍历 class Solution { public: vector<int> PrintFro ...

  2. 《剑指offer》从上往下打印二叉树

    本题来自<剑指offer> 从上往下打印二叉树 题目: 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 思路: 队列的思想. 先将根节点加入,当取该节点时候,依次将左右子树加入,直 ...

  3. 【剑指Offer】从上往下打印二叉树 解题报告(Python)

    [剑指Offer]从上往下打印二叉树 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-interviews ...

  4. 剑指offer系列20--从上到下打印二叉树

    * 20 [题目]从上往下打印出二叉树的每个节点,同层节点从左至右打印. * [思路]从根结点开始,先保存结点,再看根结点的左右结点有没有值. * 有,就将左右值放到集合中: * 根节点输出后,打印根 ...

  5. 剑指Offer 22. 从上往下打印二叉树 (二叉树)

    题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 题目地址 https://www.nowcoder.com/practice/7fe2212963db4790b57431d9ed25 ...

  6. 【剑指offer】从上向下打印二叉树

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/26089165 剑指offer上的第23题,实际上就是考察二叉树的层序遍历,详细思想能够參考 ...

  7. Go语言实现:【剑指offer】从上往下打印二叉树

    该题目来源于牛客网<剑指offer>专题. 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 不需分层,一维数组. Go语言实现: /** * Definition for a bi ...

  8. 剑指OFFER之从上往下打印二叉树(九度OJ1523)

    题目描述: 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行一个整数n(1<=n<=1000, : ...

  9. 剑指offer:从上往下打印二叉树

    题目描述: 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 解题思路: 实际就是二叉树的中序遍历问题.之前在leetcode刷过类似题目. 利用队列完成即可. 代码: /* struct Tr ...

随机推荐

  1. Qt之QEvent(所有事件的翻译)

    QEvent 类是所有事件类的基类,事件对象包含事件参数. Qt 的主事件循环(QCoreApplication::exec())从事件队列中获取本地窗口系统事件,将它们转化为 QEvents,然后将 ...

  2. [C++]Linux之图形界面编程库[curses库]之入门教程

    1. 安装 //方法一 sudo apt-get install libncurses5-dev [ ubuntu 16.04:亲测有效] //方法二 sudo apt-get install ncu ...

  3. 第三周结对项目--小学生四则运算CAI软件汇报及总结(UI/web)

    前言: 这周是和我队友苏卫喜一起结对开发,我主要是写项目文档需求分析,她是通过我的需求文档来进行做思维导图,之后我们通过思维导图一起讨论用户界面设计. 以下就是我的需求分析1.0版本 1.   软件名 ...

  4. json和jsonp的使用区别

    json和jsonp的使用区别 一.    跨域请求的概念 JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象. 二.    json和jsonp JSON是一种基于文本的数据交换方 ...

  5. bootstrap-table前端修改数据

    使用bootstrap-table显示数据,后台传回数据以后,可能需要对其做调整,如需要前端为数据添加单位 调整数据代码 $("#"+tableId).bootstrapTable ...

  6. ActiveMQ集群

    1.ActiveMQ集群介绍 1.为什么要集群? 实现高可用,以排除单点故障引起的服务中断 实现负载均衡,以提升效率为更多客户提供服务 2.集群方式 客户端集群:让多个消费者消费同一个队列 Broke ...

  7. 一份通过IPC$和lpk.dll感染方式的病毒分析报告

    样本来自52pojie论坛,从事过两年渗透开始学病毒分析后看到IPC$真是再熟悉不过. 1.样本概况 1.1 样本信息 病毒名称:3601.exe MD5值:96043b8dcc7a977b16a28 ...

  8. unicode 和 utf-8字符编码的区别

    作者:于洋链接:https://www.zhihu.com/question/23374078/answer/69732605来源:知乎著作权归作者所有,转载请联系作者获得授权.   原文:unico ...

  9. 写好shell脚本的13个技巧【转】

    有多少次,你运行./script.sh,然后输出一些东西,但却不知道它刚刚都做了些什么.这是一种很糟糕的脚本用户体验.我将在这篇文章中介绍如何写出具有良好开发者体验的 shell 脚本. 产品的最终用 ...

  10. 在docker中部署centos7镜像

    本篇文章参考自: https://www.cnblogs.com/linjj/p/5606911.html https://blog.csdn.net/u012767761/article/detai ...