1102 Invert a Binary Tree (25分)
The following is from Max Howell @twitter:
Google: 90% of our engineers use the software you wrote (Homebrew), but you can't invert a binary tree on a whiteboard so fuck off.
Now it’s your turn to prove that YOU CAN invert a binary tree!
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (≤10) which is the total number of nodes in the tree – and hence the nodes are numbered from 0 to N−1. Then N lines follow, each corresponds to a node from 0 to N−1, and gives the indices of the left and right children of the node. If the child does not exist, a -
will be put at the position. Any pair of children are separated by a space.
Output Specification:
For each test case, print in the first line the level-order, and then in the second line the in-order traversal sequences of the inverted tree. There must be exactly one space between any adjacent numbers, and no extra space at the end of the line.
Sample Input:
8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6
Sample Output:
3 7 2 6 4 0 5 1
6 5 7 4 3 2 0 1
题目大意:
给定一棵二叉树,让我们把二叉树进行翻转,所谓翻转,就是对于每一棵子树的根节点来说,我们需要交换其左右孩子。也就是,交换完的二叉树和原来的树应该是镜像对称的。题目要求我们输出翻转后的二叉树的层序遍历和中序遍历。
思路分析:
这里面主要需要解决翻转的问题。而解决翻转通常使用后序递归遍历。在遍历回溯的过程中进行交换左右子树的操作。说到这里,我们首先需要考虑的一个问题是,如何存储题目给定的这一棵二叉树。由于题目每一行输入是一个节点,而这些节点的输入并没有按照 二叉树链式存储的格式给定,说人话就是,在读入整棵树的信息之前,您并不知道这棵树的结构,我们知道如果使用链式存储,会给我们的编程带来很大麻烦。 一个比较简单的做法就是使用对象数组存储,数组的下标正好可以作为节点的 val 值。每一个数组元素存储一个Node对象,通过Node 对象的left 和 right 找到这个节点的左右孩子在数组中的位置。 比如,节点3 的left 为 1 那么我们就是知道 1号节点就是3号节点的左孩子。
如何确定哪个节点是root(根) 节点呢?因为我们的节点编号都是从 0 --N-1的 ,因次(不是任何节点的孩子节点)就是根节点。因次,我们可以设置一个boolean数组,在读取每一个节点的孩子节点数据时,在相应的boolean数组的位置标记为true 表示这个位置的节点不是一个根节点,因为它都是别人孩子了。对于空节点我们设置为-1 这样也是因为数组下标没有-1 比较容易判断。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
Left 1 | Left -1 | left 0 | left 2 | Left -1 | left -1 | left 5 | left 4 |
right -1 | Right -1 | Right -1 | right 7 | Left -1 | Right -1 | Right -1 | right 6 |
在读取数据的时候进行标记,我们会把除了 3位置以外的位置都标记为 true ,这样在后面寻找根节点的时候,false位置只有 3号位置。我们就知道 3号是根节点。 剩下的遍历其实是比较容易掌握的。我们重点就是用数组建立静态的二叉树
完整代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
//8
//1 -
//- -
//0 -
//2 7
//- -
//- -
//5 -
//4 6
public class Main {
static class Node {
int left;
int right;
public Node(int left, int right) {
this.left = left;
this.right = right;
}
}
static int nums;
static int cnts = 0;
static boolean[] notRoot;
static Node[] nodes;
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
nums = Integer.parseInt(bf.readLine().trim());
nodes = new Node[nums];
notRoot = new boolean[nums];
// 建立静态二叉树 数组中一个位置一个节点
for (int i = 0; i < nums; i++) {
String[] info = bf.readLine().trim().split(" ");
nodes[i] = new Node(-1, -1);
if (!info[0].equals("-")) {
nodes[i].left = Integer.parseInt(info[0]);
notRoot[nodes[i].left] = true;
}
if (!info[1].equals("-")) {
nodes[i].right = Integer.parseInt(info[1]);
notRoot[nodes[i].right] = true;
}
}
int root = -1; // 寻找根节点
for (int i = 0; i < nums; i++) {
if (!notRoot[i]) {
root = i;
break;
}
}
invert(root); // 翻转二叉树
LevelOrder(root); // 层序遍历
cnts = 0; // 让cnts 归0 应为层序用了一次cnts自曾,控制空格输出 现在需要再用一次
System.out.println(); // 输出换行
InorderTraver(root); // 中序遍历
}
// 翻转二叉树
static void invert(int root) {
if (root == -1) // 这是一个空节点,因为我们的节点编号是从 0 .....nums-1
return;
invert(nodes[root].left); // 递归翻转左子树
invert(nodes[root].right); // 递归翻转右子树
int left = nodes[root].left; // 下面四行是左右孩子互换,交换都是发生在递归的回溯过程中
int right = nodes[root].right;
nodes[root].left = right;
nodes[root].right = left;
}
// 二叉树的中序遍历
static void InorderTraver(int root) {
if (root == -1)
return;
InorderTraver(nodes[root].left);
System.out.print(root);
cnts++;
if (cnts != nums)
System.out.print(" ");
InorderTraver(nodes[root].right);
}
// 二叉树的层序遍历
static void LevelOrder(int root) {
Queue<Integer> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int val = queue.poll();
System.out.print(val);
cnts++;
if (cnts != nums)
System.out.print(" ");
if (nodes[val].left != -1)
queue.offer(nodes[val].left);
if (nodes[val].right != -1)
queue.offer(nodes[val].right);
}
}
}