前言
由于自己树和链表学得一般,就写写博客吧
题目
二叉树基础
题意
样例
思路
主要都写在注释里了。
说一下注释里没有的。
为什么要用vector?
由于建树不一定满足dfs序,我们不能保证编号小的节点一定在编号大的节点上方,而链表类里只存储根节点。因此不能在输入时就进行建树,应该先预处理完节点之间的“父子”关系再进行建树。
例如:
代码(仅供参考!)
#include<iostream>
#include<queue>
#include<vector>
#include<cstdio>
using namespace std;
const int maxn = 1e5+5;
vector<int> v[maxn]; // v[i].push_back(j) : i有个子节点j
int a[maxn][2]; // 最后用来输出第二行和第三行的(即节点大小和节点高度)
queue<int> q,q2; //开一个队列来输出第一行即层序遍历
//node 记录每个节点的情况
struct node{
int val; //节点编号
node* left; //左儿子
node* right; //右儿子
int hei; //高度
int siz; //大小
};
int n;
class tree{
public:
node firstnode; //根节点 (这里为了方便写在public上,建议写在private里)
tree();
~tree(){}
void build(node *tmp); //建树
void solve(node *tmp); //搜索,处理节点的size和height
void get(node *tmp); //再搜一遍,把节点的size和height按顺序存在数组a[][2]中。
};
tree::tree(){
firstnode.val = 1;firstnode.left = NULL;
firstnode.right = NULL;firstnode.hei = 1;
firstnode.siz = 1;
}
//建树
void tree::build(node *tmp){
//若当前节点为空,终止
if(tmp==NULL)
return;
//若有左儿子,则建立该节点并进入
if(v[tmp->val][0]!=-1){
tmp->left = new node{v[tmp->val][0],NULL,NULL,1,1};
build(tmp->left);
}
//若有右儿子,则建立该节点并进入
if(v[tmp->val][1]!=-1){
tmp->right = new node{v[tmp->val][1],NULL,NULL,1,1};
build(tmp->right);
}
return;
}
//搜索,处理节点的size和height
void tree::solve(node *tmp){
//每个节点的size = 左儿子的size + 右儿子的size .
//每个节点的height = max(左儿子的height , 右儿子的height) .
//因为我们会先访问父亲节点再访问儿子节点 ,因此采用树形结构里常用的回溯法进行赋值 .
if(tmp->left!=NULL){
solve(tmp->left); //先进入下一层
tmp->siz += tmp->left->siz; //回来以后再赋值
}
if(tmp->right!=NULL){
solve(tmp->right); //先进入下一层
tmp->siz += tmp->right->siz; //回来以后再赋值
}
if(tmp->left!=NULL||tmp->right!=NULL){
if(tmp->left!=NULL&&tmp->right!=NULL)
tmp->hei = max(tmp->left->hei,tmp->right->hei)+1;
else if(tmp->left!=NULL)
tmp->hei = tmp->left->hei+1;
else
tmp->hei = tmp->right->hei+1;
}
}
//再搜一遍,把节点的size和height按顺序存在数组a[][2]中。
void tree::get(node *tmp){
//常规搜索,因为要求是顺序输出size 和 height ,因此把它们存在a数组中
a[tmp->val][0] = tmp->siz;
a[tmp->val][1] = tmp->hei;
if(tmp->left!=NULL){
get(tmp->left);
}
if(tmp->right!=NULL){
get(tmp->right);
}
}
//quary 输出a数组,即size 和 height
void quary(){
for(int i=1;i<=n;i++)
printf("%d ",a[i][0]);
printf("\n");
for(int i=1;i<=n;i++)
printf("%d ",a[i][1]);
printf("\n");
}
// get_num 输出层序遍历, 采用宽度优先遍历(bfs)的方法 ,队列实现。
void get_num(){
q.push(1); //从根开始,弹出一个元素的同时 压入它的儿子(即BFS)。这样,根据队列先进先出的特性就可以实现层序遍历,
while(!q.empty()){
int now = q.front();
printf("%d ",now);
q.pop();
q2.push(now);
if(v[now][0]!=-1)
q.push(v[now][0]);
if(v[now][1]!=-1)
q.push(v[now][1]);
}
printf("\n");
}
tree t;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int a,b;
scanf("%d %d",&a,&b);
v[i].push_back(a);
v[i].push_back(b);
}
get_num();
t.build(&t.firstnode);
t.solve(&t.firstnode);
//cout<<"*test*"<<endl;
t.get(&t.firstnode);
quary();
return 0;
}
题目
二叉树遍历
题意
思路
这题和这题很像:
洛谷 P1030 求先序排列,
链接:https://www.luogu.com.cn/problem/P1030 。
但是由前序,中序找后序要比由中序,后序找前序简单一点。
记得三种遍历应该不难写,主要是递归调用的过程。直接上代码吧。
代码(仅供参考!)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005;
int a[maxn];
int b[maxn];
int now = 0;
int n;
void check(int l,int r){
if(now>=n){
return;
}
if(l>r){
return;
}
int fa = a[now++];
for(int i=l;i<=r;i++){
if(b[i]==fa){
check(l,i-1);
check(i+1,r);
}
}
cout<<fa<<" ";
}
int main(){
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
cin>>b[i];
int l = 0,r = n-1;
check(l,r);
}