面试题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();
}
}