【二叉树遍历】
二叉树遍历
※注意左右子树存在时才能继续递归!
前序遍历
根节点->左子树->右子树
void pre_order(int x){
cout<<x;
if(tree[x].left!=0){
pre_order(tree[x].left);
}
if(tree[x].right!=0){
pre_order(tree[x].right);
}
}
中序遍历
左子树->根节点->右子树
void in_order(int x){
if(tree[x].left!=0){
in_order(tree[x].left);
}
cout<<x;
if(tree[x].right!=0){
in_order(tree[x].right);
}
}
后序遍历
左子树->右子树->根节点
void after_order(int x){
if(tree[x].left!=0){
after_order(tree[x].left);
}
if(tree[x].right!=0){
after_order(tree[x].right);
}
cout<<x;
}
中+先/后 -> 求另一个
后序遍历:最后一个为根(如ABCD,则根为D)
先序遍历:第一个为根
思路:要不断找根
【求先序为例】
中序ACGDBHZKX,后序CDGAHXKZB,首先可找到主根B
那么我们找到中序遍历中的B,由这种遍历的性质,可将中序遍历分为ACGD和HZKX两棵子树,
那么对应可找到后序遍历CDGA和HXKZ(从头找即可)
从而问题就变成求1.中序遍历ACGD,后序遍历CDGA的树 2.中序遍历HZKX,后序遍历HXKZ的树
接着递归,按照原先方法,找到1.子根A,再分为两棵子树2.子根Z,再分为两棵子树
就按这样一直做下去(先输出根,再递归)
step1:找到根并输出
step2:将中序,后序各分为左右两棵子树
step3:递归,重复step1,2
【不同点】
求先序:先输出根再dfs找根
求后序:先dfs找根再输出根
求先序遍历
#include<bits/stdc++.h>
using namespace std;
string s1,s2;
void dfs(string in,string after){
if(in.size()>0){//递归出口:根节点都被遍历完了
int l=in.size();
char c=after[after.size()-1];
int k=in.find(c);
cout<<c;
dfs(in.substr(0,k),after.substr(0,k));
dfs(in.substr(k+1,l-k),after.substr(k,l-k-1));//注意这里要-1!!!从k开始
}
}
int main(){
cin>>s1>>s2;
dfs(s1,s2);
return 0;
}
求后序遍历
#include<bits/stdc++.h>
using namespace std;
string s1,s2;
void dfs(string in,string be){
int l=in.size();
if(l>0){
char c=be[0];
int k=in.find(c);
dfs(in.substr(0,k),be.substr(1,k));
dfs(in.substr(k+1),be.substr(k+1));//默认到结尾
cout<<c;
}
}
int main(){
cin>>s1>>s2;
dfs(s1,s2);
return 0;
}
变式:拓展二叉树
https://fjnuacm.top/d/minor/p/248?tid=66bcbaa67d902b243e152aed
【链式存储】
//树的链式存储
#include<bits/stdc++.h>
using namespace std;
typedef struct node;//声明:有node这样一个结构体
typedef node *tree;//指向node结构体的指针类型
struct node{
char data;
tree l,r;//左子树、右子树
};
tree bt;
int i=-1;//下面是++i:从-1开始
string s;
void add(tree &bt){
if(s[++i]!='.'){
bt=new node;//分配内存空间存储树
bt->data=s[i];
add(bt->l);
add(bt->r);
}
else bt=NULL;
}
void in_order(tree u){
if(u){
in_order(u->l);
cout<<u->data;
in_order(u->r);
}
}
void after_order(tree u){
if(u){
after_order(u->l);
after_order(u->r);
cout<<u->data;
}
}
int main(){
cin>>s;
add(bt);
in_order(bt);
cout<<'\n';
after_order(bt);
return 0;
}
【数组存储】
//只要是二叉树就可以表示左右儿子:2*k 2*k+1
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char tree[N];
string s;
int now=0,n;//now作为字符串指针
void add(int root,int pos){//root对应s下标 pos对应树下标
tree[pos]=s[root];// 将 s 中的字符存入树节点
now++;
//记住这里是:如果当前字符不为'.'
if(s[now]!='.') add(now,pos*2);//递归存储左子树
if(now>n) exit(0);//立即终止函数
now++;
if(s[now]!='.') add(now,pos*2+1);//递归存储右子树
if(now>n) exit(0);
}
void readin(int u){//中序遍历
//0为空节点 不输出
if(tree[u*2]!=0) readin(u*2);//左子树
cout<<tree[u];
if(tree[u*2+1]!=0) readin(u*2+1);//右子树
}
void reada(int u){//后序遍历
if(tree[u*2]!=0) reada(u*2);//左子树
if(tree[u*2+1]!=0) reada(u*2+1);//右子树
cout<<tree[u];
}
int main(){
cin>>s;
n=s.size();
add(0,1);//树根节点从1开始
readin(1);
cout<<'\n';
reada(1);
return 0;
}
FBI树
https://fjnuacm.top/d/minor/p/249?tid=66bcbaa67d902b243e152aed
※有些树的题目可以不用存树
※思路:
存树的过程->先序遍历 二分+递归处理
题目要求后序遍历->直接输出即可
//从上往下存储:二分+递归存储即可
#include<bits/stdc++.h>
using namespace std;
const int N=1e8+10;
int n;
string s;
void add(int x,int y){
if(y>x){//递归出口:只剩下1个数的时候
int mid=(x+y)>>1;
add(x,mid);
add(mid+1,y);
}
//求后序遍历:不需要存树->左右子树分别操作然后输出根节点
int B=1,I=1;
//判断类型:直接一个个找即可
for(int i=x;i<=y;i++){
if(s[i]=='1') I=0;
else if(s[i]=='0') B=0;
}
if(B) cout<<'I';//注意这里要反过来!没有这个数就是另一种类型
else if(I) cout<<'B';
else cout<<'F';
}
int main(){
scanf("%d",&n);
cin>>s;
add(0,(1<<n)-1);//字符串长度:2^n-1 即 (1<<n)-1
return 0;
}