携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第31天,点击查看活动详情
题目描述:
“侧影”就是从左侧或者右侧去观察物体所看到的内容。例如上图中男生的侧影是从他右侧看过去的样子,叫“右视图”;女生的侧影是从她左侧看过去的样子,叫“左视图”。
520 这个日子还在打比赛的你,也就抱着一棵二叉树左看看右看看了……
我们将二叉树的“侧影”定义为从一侧能看到的所有结点从上到下形成的序列。例如下图这棵二叉树,其右视图就是 { 1, 2, 3, 4, 5 },左视图就是 { 1, 6, 7, 8, 5 }。
于是让我们首先通过一棵二叉树的中序遍历序列和后序遍历序列构建出一棵树,然后你要输出这棵树的左视图和右视图。
输入格式:
输入第一行给出一个正整数 N (≤20),为树中的结点个数。随后在两行中先后给出树的中序遍历和后序遍历序列。树中所有键值都不相同,其数值大小无关紧要,都不超过 int 的范围。
输出格式:
第一行输出右视图,第二行输出左视图,格式如样例所示。
输入样例:
在这里给出一组输入。例如:
8
6 8 7 4 5 1 3 2
8 5 4 7 6 3 2 1
输出样例:
在这里给出相应的输出。例如:
R: 1 2 3 4 5
L: 1 6 7 8 5
作者的话:如果你是一名比赛的人员,二叉树的建树算法一定是非常重要的,在天梯赛等编程比赛中常考,好先看看这道题
题目通俗易懂,但是操作起来有点麻烦,细细拆分题目无疑是分为两大步骤——建树和层次遍历存入数组
建树
题目给出了中序遍历和后序遍历,我们需要根据这两个序列来建树,我们要根据二叉树建树的原则来理解,以题目为例子
1.首先找根节点,由后序遍历可知最末尾的就是根节点,于是1为根节点
2.接着看根节点在中序遍历的位置,1的右边是32,所以3和2是1的右子树,同时看看在后序遍历中2在3的后面,所以1连接2,2是1的右子树
3.而且3在中序遍历中在2的左边,所以3是2的左子树
4.然后看1在中序遍历的左边,6,8,7,4,5都是1的左子树,而在后序遍历中6在最末尾,所以6与1相连是1的左子树
5.接着看6在中序遍历的位置,8,7,4,5都是6的右子树,在后序遍历可知7是与6相连的结点
6.然后看7在中序遍历的结果,8是7的左子树,4和5是7的右子树,在8,4,5中4无疑是与7相连的右子树
7.接下来是5,5是4的右子树
8.最后是8,8在中序遍历可以知识7的左子树
dfs建树算法
void dfs(node*& root, int left, int right) {
if (left <= right) {
int temp = left;
root = new node;
root->data = last[i];
root->lchild = root->rchild = NULL;
while (mid[temp] != last[i])
temp++;
i--;//main函数先置条件是i=n-1;
dfs(root->rchild, temp + 1, right);
dfs(root->lchild, left, temp - 1);
}
}
利用刚刚讲的思路,创建了这样的dfs算法,不断地从后序遍历数组的末尾往前迭代,不断找下一个结点,在中序遍历中找到与之对应的数,这就是建树dfs算法
层次遍历存数组算法
大家都知道二叉树的层次遍历吧,如果不知道可以看看我的这两篇文章:数据结构——排序二叉树总代码部分 - 掘金 (juejin.cn)、关于二叉树操作的进阶 - 掘金 (juejin.cn)
层次遍历需要用到队列的思维,我们这道题目需要统计每一层最左边和最右边的值存入数组之中
1.先将根节点存入队列,进行循环
2.这是一个二层循环,进行第二层循环时有前置条件,count计数为队列当前的大小(size),计数器归零
3.二层循环中count是循环边界,结点指针指向对头元素
4.判断计数器是否为0,是的话说明是这一层最左边的元素,此时存入vector的数组
5.先出队,计数器加1(每次出队计数器都加一方便判断),判断计数器是否到达count边界,到了的话说明此时就是这一层的最右边,存入vector数组(左右两个vector数组不同)
6.接着按照层次遍历的基本模板进行左右孩子的入队,这就是一次二层循环
bfs层次遍历代码
void bfs(node* root) {
queue<node*>q;
q.push(root);
while (!q.empty()) {
int count = q.size();
int cnt = 0;
for (int i = 0; i < count; i++) {
node* p = q.front();
if (cnt == 0)
L.push_back(p->data);
q.pop();
cnt++;
if (cnt == count)
R.push_back(p->data);
if (p->lchild)
q.push(p->lchild);
if (p->rchild)
q.push(p->rchild);
}
}
}
总思路讲解及细节
- 要创建全局变量如下(中序遍历数组,后序遍历数组)
- dfs建树方法
- bfs层次遍历算法
- 最后的分别用两个vector数组输出
总代码展示:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
struct node {
int data;
node* lchild;
node* rchild;
};
int mid[25], last[25];
int i;
vector<int>R, L;
void dfs(node*& root, int left, int right) {
if (left <= right) {
int temp = left;
root = new node;
root->data = last[i];
root->lchild = root->rchild = NULL;
while (mid[temp] != last[i])
temp++;
i--;
dfs(root->rchild, temp + 1, right);
dfs(root->lchild, left, temp - 1);
}
}
void bfs(node* root) {
queue<node*>q;
q.push(root);
while (!q.empty()) {
int count = q.size();
int cnt = 0;
for (int i = 0; i < count; i++) {
node* p = q.front();
if (cnt == 0)
L.push_back(p->data);
q.pop();
cnt++;
if (cnt == count)
R.push_back(p->data);
if (p->lchild)
q.push(p->lchild);
if (p->rchild)
q.push(p->rchild);
}
}
}
int main()
{
int n;
cin >> n;
i = n - 1;
for (int i = 0; i < n; i++)
cin >> mid[i];
for (int i = 0; i < n; i++)
cin >> last[i];
node* root;
dfs(root, 0, n - 1);
bfs(root);
cout << "R:";
for (int i = 0; i < R.size(); i++)
cout << " " << R[i];
cout << endl;
cout << "L:";
for (int i = 0; i < L.size(); i++)
cout << " " << L[i];
}
作者的话:让我们一同加油前行~~~