【二叉树遍历】

二叉树遍历

※注意左右子树存在时才能继续递归

前序遍历

根节点->左子树->右子树

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;
}
posted @ 2024-11-09 01:39  White_ink  阅读(0)  评论(0编辑  收藏  举报