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

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

题目 

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

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

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

思路

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

  1. /*
  2. * 不分行从上往下打印二叉树
  3. */
  4. // 题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。
  5. public void printTree1(TreeNode root) {
  6. if (root == null)
  7. return;
  8. LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
  9. queue.offer(root);
  10. TreeNode node = null;
  11. while (queue.size()!=0) {
  12. node = queue.poll();
  13. System.out.print(node.val + " ");
  14. if (node.left != null)
  15. queue.offer(node.left);
  16. if (node.right != null)
  17. queue.offer(node.right);
  18. }
  19. System.out.println();
  20. }

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

  1. /*
  2. * 分行从上到下打印二叉树
  3. */
  4. // 题目:从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层
  5. // 打印到一行。
  6. public void printTree2(TreeNode root) {
  7. if (root == null)
  8. return;
  9. LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
  10. queue.offer(root);
  11. TreeNode node = null;
  12. int pCount = 0; //当前层结点数目
  13. int nextCount = 1; //下一层结点数目
  14. while (!queue.isEmpty()) {
  15. pCount = nextCount;
  16. nextCount = 0;
  17. //打印当前层数字,并计算下一层结点数目
  18. for (int i = 1; i <= pCount; i++) {
  19. node = queue.poll();
  20. System.out.print(node.val + " ");
  21. if (node.left != null) {
  22. queue.offer(node.left);
  23. nextCount++;
  24. }
  25. if (node.right != null) {
  26. queue.offer(node.right);
  27. nextCount++;
  28. }
  29. }
  30. System.out.println();
  31. }
  32. }

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

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

  1. /*
  2. * 之字形打印二叉树
  3. */
  4. // 题目:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺
  5. // 序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,
  6. // 其他行以此类推。
  7. /**
  8. * 自己开始想的方法,采用数组存储每层的数字,根据当前层数确定正反向打印数组
  9. */
  10. public void printTree3_1(TreeNode root) {
  11. if (root == null)
  12. return;
  13. LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
  14. queue.offer(root);
  15. TreeNode node = null;
  16. int pCount = 0; //当前层结点数目
  17. int nextCount = 1; //下一层结点数目
  18. int level=1; //层数
  19. int[] pNums=null; //用于存储当前层的数字
  20. while (!queue.isEmpty()) {
  21. pCount = nextCount;
  22. nextCount = 0;
  23. pNums=new int[pCount];
  24. //存储当前层数字,并计算下一层结点数目
  25. for (int i = 0; i < pCount; i++) {
  26. node = queue.poll();
  27. pNums[i]=node.val;
  28. if (node.left != null) {
  29. queue.offer(node.left);
  30. nextCount++;
  31. }
  32. if (node.right != null) {
  33. queue.offer(node.right);
  34. nextCount++;
  35. }
  36. }
  37. //根据当前层数确定正向或者反向打印数组
  38. if((level&1)!=0 ) {
  39. for(int i=0;i<pCount;i++) {
  40. System.out.print(pNums[i]+" ");
  41. }
  42. }else {
  43. for(int i=pCount-1;i>=0;i--) {
  44. System.out.print(pNums[i]+" ");
  45. }
  46. }
  47. level++;
  48. System.out.println();
  49. }
  50. }

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

  1. /**
  2. * 采用两个栈进行操作的方法
  3. */
  4. public void printTree3_2(TreeNode root) {
  5. if (root == null)
  6. return;
  7. Stack<TreeNode> stack1 = new Stack<TreeNode>();
  8. Stack<TreeNode> stack2 = new Stack<TreeNode>();
  9. TreeNode node = null;
  10. stack1.push(root);
  11. while(!stack1.empty() || !stack2.empty()) {
  12. while(!stack1.empty()) {
  13. node=stack1.pop();
  14. System.out.print(node.val + " ");
  15. if (node.left != null)
  16. stack2.push(node.left);
  17. if (node.right != null)
  18. stack2.push(node.right);
  19. }
  20. System.out.println();
  21. while(!stack2.empty()) {
  22. node=stack2.pop();
  23. System.out.print(node.val + " ");
  24. if (node.right != null)
  25. stack1.push(node.right);
  26. if (node.left != null)
  27. stack1.push(node.left);
  28. }
  29. System.out.println();
  30. }
  31. }

  

测试算例 

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

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

完整Java代码

含测试代码:

  1. import java.util.LinkedList;
  2. import java.util.Stack;
  3. /**
  4. *
  5. * @Description 面试题32:从上往下打印二叉树
  6. *
  7. * @author yongh
  8. */
  9.  
  10. public class PrintTreeFromTopToBottom {
  11. public class TreeNode {
  12. int val = 0;
  13. TreeNode left = null;
  14. TreeNode right = null;
  15.  
  16. public TreeNode(int val) {
  17. this.val = val;
  18. }
  19. }
  20.  
  21. /*
  22. * 不分行从上往下打印二叉树
  23. */
  24. // 题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。
  25. public void printTree1(TreeNode root) {
  26. if (root == null)
  27. return;
  28. LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
  29. queue.offer(root);
  30. TreeNode node = null;
  31. while (queue.size()!=0) {
  32. node = queue.poll();
  33. System.out.print(node.val + " ");
  34. if (node.left != null)
  35. queue.offer(node.left);
  36. if (node.right != null)
  37. queue.offer(node.right);
  38. }
  39. System.out.println();
  40. }
  41.  
  42. /*
  43. * 分行从上到下打印二叉树
  44. */
  45. // 题目:从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层
  46. // 打印到一行。
  47. public void printTree2(TreeNode root) {
  48. if (root == null)
  49. return;
  50. LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
  51. queue.offer(root);
  52. TreeNode node = null;
  53. int pCount = 0; //当前层结点数目
  54. int nextCount = 1; //下一层结点数目
  55. while (!queue.isEmpty()) {
  56. pCount = nextCount;
  57. nextCount = 0;
  58. //打印当前层数字,并计算下一层结点数目
  59. for (int i = 1; i <= pCount; i++) {
  60. node = queue.poll();
  61. System.out.print(node.val + " ");
  62. if (node.left != null) {
  63. queue.offer(node.left);
  64. nextCount++;
  65. }
  66. if (node.right != null) {
  67. queue.offer(node.right);
  68. nextCount++;
  69. }
  70. }
  71. System.out.println();
  72. }
  73. }
  74.  
  75. /*
  76. * 之字形打印二叉树
  77. */
  78. // 题目:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺
  79. // 序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,
  80. // 其他行以此类推。
  81. /**
  82. * 自己开始想的方法,采用数组存储每层的数字,根据当前层数确定正反向打印数组
  83. */
  84. public void printTree3_1(TreeNode root) {
  85. if (root == null)
  86. return;
  87. LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
  88. queue.offer(root);
  89. TreeNode node = null;
  90. int pCount = 0; //当前层结点数目
  91. int nextCount = 1; //下一层结点数目
  92. int level=1; //层数
  93. int[] pNums=null; //用于存储当前层的数字
  94. while (!queue.isEmpty()) {
  95. pCount = nextCount;
  96. nextCount = 0;
  97. pNums=new int[pCount];
  98. //存储当前层数字,并计算下一层结点数目
  99. for (int i = 0; i < pCount; i++) {
  100. node = queue.poll();
  101. pNums[i]=node.val;
  102. if (node.left != null) {
  103. queue.offer(node.left);
  104. nextCount++;
  105. }
  106. if (node.right != null) {
  107. queue.offer(node.right);
  108. nextCount++;
  109. }
  110. }
  111. //根据当前层数确定正向或者反向打印数组
  112. if((level&1)!=0 ) {
  113. for(int i=0;i<pCount;i++) {
  114. System.out.print(pNums[i]+" ");
  115. }
  116. }else {
  117. for(int i=pCount-1;i>=0;i--) {
  118. System.out.print(pNums[i]+" ");
  119. }
  120. }
  121. level++;
  122. System.out.println();
  123. }
  124. }
  125.  
  126. /**
  127. * 采用两个栈进行操作的方法
  128. */
  129. public void printTree3_2(TreeNode root) {
  130. if (root == null)
  131. return;
  132. Stack<TreeNode> stack1 = new Stack<TreeNode>();
  133. Stack<TreeNode> stack2 = new Stack<TreeNode>();
  134. TreeNode node = null;
  135. stack1.push(root);
  136. while(!stack1.empty() || !stack2.empty()) {
  137. while(!stack1.empty()) {
  138. node=stack1.pop();
  139. System.out.print(node.val + " ");
  140. if (node.left != null)
  141. stack2.push(node.left);
  142. if (node.right != null)
  143. stack2.push(node.right);
  144. }
  145. System.out.println();
  146. while(!stack2.empty()) {
  147. node=stack2.pop();
  148. System.out.print(node.val + " ");
  149. if (node.right != null)
  150. stack1.push(node.right);
  151. if (node.left != null)
  152. stack1.push(node.left);
  153. }
  154. System.out.println();
  155. }
  156. }
  157.  
  158. //============测试代码==============
  159. private void test(int testNum,TreeNode root) {
  160. System.out.println("=========test"+testNum+"===========");
  161. System.out.println("method1:");
  162. printTree1(root);
  163. System.out.println("method2:");
  164. printTree2(root);
  165. System.out.println("method3_1:");
  166. printTree3_1(root);
  167. System.out.println("method3_2:");
  168. printTree3_2(root);
  169. }
  170.  
  171. //null
  172. private void test1() {
  173. TreeNode node=null;
  174. test(1, node);
  175. }
  176.  
  177. //单个结点
  178. private void test2() {
  179. TreeNode node=new TreeNode(1);
  180. test(2, node);
  181. }
  182.  
  183. //左斜
  184. private void test3() {
  185. TreeNode node1=new TreeNode(1);
  186. TreeNode node2=new TreeNode(2);
  187. TreeNode node3=new TreeNode(3);
  188. node1.left=node2;
  189. node2.left=node3;
  190. test(3, node1);
  191. }
  192.  
  193. //右斜
  194. private void test4() {
  195. TreeNode node1=new TreeNode(1);
  196. TreeNode node2=new TreeNode(2);
  197. TreeNode node3=new TreeNode(3);
  198. node1.right=node2;
  199. node2.right=node3;
  200. test(4, node1);
  201. }
  202.  
  203. //完全二叉树
  204. private void test5() {
  205. TreeNode[] nodes = new TreeNode[15];
  206. for(int i=0;i<15;i++) {
  207. nodes[i]= new TreeNode(i+1);
  208. }
  209. for(int i=0;i<7;i++) {
  210. nodes[i].left=nodes[2*i+1];
  211. nodes[i].right=nodes[2*i+2];
  212. }
  213. test(5, nodes[0]);
  214. }
  215.  
  216. public static void main(String[] args) {
  217. PrintTreeFromTopToBottom demo= new PrintTreeFromTopToBottom();
  218. demo.test1();
  219. demo.test2();
  220. demo.test3();
  221. demo.test4();
  222. demo.test5();
  223. }
  224. }

  

  1. =========test1===========
  2. method1:
  3. method2:
  4. method3_1:
  5. method3_2:
  6. =========test2===========
  7. method1:
  8.  
  9. method2:
  10.  
  11. method3_1:
  12.  
  13. method3_2:
  14.  
  15. =========test3===========
  16. method1:
  17.  
  18. method2:
  19.  
  20. method3_1:
  21.  
  22. method3_2:
  23.  
  24. =========test4===========
  25. method1:
  26.  
  27. method2:
  28.  
  29. method3_1:
  30.  
  31. method3_2:
  32.  
  33. =========test5===========
  34. method1:
  35.  
  36. method2:
  37.  
  38. method3_1:
  39.  
  40. 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. 攻击WEP加密无线网络

    1.介绍 针对客户端环境和无客户端环境下破解WEP的几类方法. 有客户端环境: 一般当前无线网络中存在活动的无线客户端环境,即有用户通过无线连接到无线AP上并正在进行上网等操作时. 无客户端环境: 1 ...

  2. VS中空项目、win32项目、控制台程序的区别(转)

    空项目,大多数想单纯创建c++工程的新同学,打开vs后很可能不知道选择创建什么工程,这时候请相信我,空项目是你最好的选择.因为空工程不包含任何的源代码文件,接下来你只需要在相应的源代码文件夹和头文件文 ...

  3. Linux常用命令(一)查看日志

    当日志文件存储很大时,需要Linux命令查看: Log 在目录 /var/log/   下 常用命令: tail head grep sed cat tac https://blog.csdn.net ...

  4. mysql 原理 ~ sql执行

    一 普通sql执行的具体过程1 连接器  管理连接,权限验证2 分析器  词法分析,语法分析   比如 数据表和数据列是否存在, 别名是否有歧义,是否符合标准sql语法等3 优化器检测   执行计划生 ...

  5. mongodb系列~mongo常用命令

    mongodb常用命令大全1 索引相关命令 db.chenfeng.ensureIndex({"riqi":1}) 添加索引会阻塞nohup mongo --eval " ...

  6. mysql 原理 ~ checkpoint

    一 简介:今天咱们来聊聊checkpoint 二 定义: checkpoin是重做日志对数据页刷新到磁盘的操作做的检查点,通过LSN号保存记录,作用是当发生宕机等crash情况时,再次启动时会查询ch ...

  7. 解决jdk1.7,1.8共存问题小思

    一 起因 随着jdk1.9呼之欲出之势,准备花点时间把jdk1.8搞掉,于是准备下一个项目的依赖改为jdk1.8,先去下载安装,安装好之后电脑上就存在两个版本的jdk.然后将两个版本的jdk路径都配置 ...

  8. Java注解之Retention、Documented、Target、Inherited介绍

    先看代码,后面一个个来解析: @Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.METHOD, ElementType. ...

  9. BFGS算法(转载)

    转载链接:http://blog.csdn.net/itplus/article/details/21897443 这里,式(2.38)暂时不知如何证出来,有哪位知道麻烦给个思路.

  10. [转]GDB-----2.watchpoint

    TODO需要在ARM下验证 1. 前言 watchpoint,顾名思义,其一般用来观察某个变量/内存地址的状态(也可以是表达式),如可以监控该变量/内存值是否被程序读/写情况. 在gdb中可通过下面的 ...