小明看树 (反转二叉树 + 二叉树的左右视图)

小明看树 (反转二叉树 + 二叉树的左右视图)

题目描述

这一天小明放学回家没带钥匙,无聊的他只能在楼下来回踱步。

这时他发现楼下种着一棵二叉树,他围着二叉树转了几圈,发现一颗二叉树从左边和从右边看到的数字是不一样的:

在这里插入图片描述

对于图中的二叉树,他从左边能看到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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值