题目
(一)从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。
(二)从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行。
(三)请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
思路
1、每次打印一个节点的时候,如果该节点有子节点,则把该节点的子节点放到一个队列的末尾。接下来到队列的头部,取出最早进入队列的节点,重复前面的打印操作,直到队列中所有的节点都被打印出来。
2、和题(一)类似,也是准备一个队列来保存将要打印的变量,为了把二叉树的每一行单独打印到一行里,我们需要两个变量:一个变量表示在当前层中还没有打印的节点数,另一个变量表示下一层节点的数目。
3、准备两个栈:对于不同层的结点,一个栈用于正向存储,一个栈用于逆向存储,打印出来就正好是相反方向。
代码
package myNewSwordOffer;
import java.util.LinkedList;
import java.util.Stack;
public class printFromTopToBottom {
public static class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
}
}
//从上往下层次打印二叉树的数值
public static void printTree1(TreeNode root) {
if(root == null) {
return;
}
//申请一个队列
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
//将根节点添加到队列中
queue.offer(root);
TreeNode node = null;
//当队列的大小不为0的时候,
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 static 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 static void printTree3(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();
}
}
public static 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:");
printTree3(root);
}
//null
public static void test1() {
TreeNode node = null;
test(1, node);
}
//单个节点
public static void test2() {
TreeNode node = new TreeNode(1);
test(2, node);
}
//左斜
public static void test3() {
TreeNode node1 = new TreeNode(1);
TreeNode node2 = new TreeNode(2);
TreeNode node3 = new TreeNode(3);
node1.left = node2;
node2.left = node3;
test(4, node1);
}
//右斜
public static 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);
}
//完全二叉树
public static 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) {
test1();
test2();
test3();
test4();
test5();
}
}
小结
1、从上往下遍历二叉树,从本质上来讲就是广度优先遍历二叉树。
2、不管是广度优先遍历有向图还是树,都要用到队列。套路是:
首先,把起始节点(对树而言是根节点)放入队列。
然后,每次从队列的头部取出一个节点,遍历这个节点可以到达的节点(对树而言是子节点)都一次放入队列。
重复该过程,知道队列中的节点全都被遍历为止。