小明看树 (反转二叉树 + 二叉树的左右视图)
题目描述
这一天小明放学回家没带钥匙,无聊的他只能在楼下来回踱步。
这时他发现楼下种着一棵二叉树,他围着二叉树转了几圈,发现一颗二叉树从左边和从右边看到的数字是不一样的:
对于图中的二叉树,他从左边能看到8 6 4 2 7,从右边可以看到8 5 1 2 7。
这不禁让他陷入了思考:如果把每个节点的左右孩子都交换位置,从左边和从右边看到的数字会有什么变化呢?
请帮助小明解决这个难题。
输入描述
第一行给定正整数n(1 ≤ n ≤ 10^3)和正整数x(1 ≤ x ≤ n),分别代表原始二叉树的节点个数和根节点编号。
接下来n行,按照1 ~ n的顺序给出原始树的节点编号ai,节点左孩子编号bi和右孩子编号ci(1 ≤ ai, bi, ci ≤ n),
没有左孩子或右孩子的位置用-1代替。
输出描述
输出2行,第1行为变化后小明从左边看到的数字,第2行为小明从右边看到的数字,
数字顺序均为从上到下,两个数字用空格隔开。
实例1
输入
8 8
1 2 -1
2 -1 7
3 -1 -1
4 -1 -1
5 -1 1
6 4 3
7 -1 -1
8 6 5
输出
8 5 1 2 7
8 6 4 2 7
题解:
题目要求先将二叉树反转,然后求二叉树的左视图和右视图。
将二叉树每一层节点分别存储下来,二叉树的左视图就是每一层最左边的节点,右视图就是每一层最右边的节点。
首先建树,题目要求把每个节点的左右孩子都交换位置,可以先建树再反转二叉树:
tree invertTree(tree node) { // 反转二叉树
if (node == NULL) {
return NULL;
}
tree temp = node->l;
node->l = node->r;
node->r = temp;
invertTree(node->l);
invertTree(node->r);
return node;
}
对于本题可以在读入的时候直接把左孩子读成右孩子,右孩子读成左孩子,这样比较简单:
for (int i = 0; i < n; i ++) { // 建树,左右孩子交换
int a, b, c;
cin >> a >> b >> c;
if (b != -1) tree[a]->r = tree[b];
if (c != -1) tree[a]->l = tree[c];
}
接着我们需要对二叉树进行层次遍历。因为我们要知道二叉树节点的深度才能知道节点在第几层,所以我们可以
在节点结构体中增加深度deep这一个属性:
typedef struct node {
int n, deep; // deep为节点深度,默认为1
struct node *l, *r;
node() {
deep = 1; l = NULL; r = NULL;
}
} *Tree;
在层次遍历中新加入队列的deep就等于父节点的deep + 1:
void level(Tree t) { // 层次遍历
queue<Tree> qu;
qu.push(t);
while (qu.size() > 0) {
Tree top = qu.front();
vt[top->deep].push_back(top->n); // 记录每一层的节点
mx = max(mx, top->deep); // 记录最大深度
if (top->l != NULL) {
top->l->deep = top->deep + 1; // 节点深度等于父节点深度 + 1
qu.push(top->l);
}
if (top->r != NULL) {
top->r->deep = top->deep + 1;
qu.push(top->r);
}
qu.pop();
}
}
知道了每个节点的深度,我们就可以在层次遍历中按照深度将深度相同的节点放到同一个vector[deep]中,记得记录一下出现过的最大深度mx,求左视图只需要从浅到深输出vector[1 ~ mx]每一层第一个编号,右视图同理从浅到深输出vector[1 ~ mx]每一层末尾的编号。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef struct node {
int n, deep; // deep为节点深度,默认为1
struct node *l, *r;
node() {
deep = 1; l = NULL; r = NULL;
}
} *Tree;
Tree tree[1005];
vector<int> vt[1005]; // 分别存储深度为1 ~ n的节点
int mx = -0x3f3f3f3f; // 记录最大深度
void level(Tree t) { // 层次遍历
queue<Tree> qu;
qu.push(t);
while (qu.size() > 0) {
Tree top = qu.front();
vt[top->deep].push_back(top->n); // 记录每一层的节点
mx = max(mx, top->deep); // 记录最大深度
if (top->l != NULL) {
top->l->deep = top->deep + 1; // 节点深度等于父节点深度 + 1
qu.push(top->l);
}
if (top->r != NULL) {
top->r->deep = top->deep + 1;
qu.push(top->r);
}
qu.pop();
}
}
int main() {
int n, x;
cin >> n >> x;
for (int i = 1; i <= n; i ++) { // 初始化节点数组
tree[i] = new node;
tree[i]->n = i;
}
for (int i = 0; i < n; i ++) { // 建树,左右孩子交换
int a, b, c;
cin >> a >> b >> c;
if (b != -1) tree[a]->r = tree[b];
if (c != -1) tree[a]->l = tree[c];
}
level(tree[x]); // 从树根x开始层次遍历
for (int i = 1; i <= mx; i ++) cout << vt[i][0] << ' '; // 输出每一层最左节点
cout << '\n';
for (int i = 1; i <= mx; i ++) cout << vt[i][vt[i].size() - 1] << ' '; // 输出每一层最右节点
cout << '\n';
return 0;
}