oj做题---树

1 基本数组建树

①求树高(后序)

整体看是求左树高和右树高中高一点的那颗树 +1

本质上就是:左、右、根

关键点:我到了一个空点,要返回给我的父节点什么信息

第一种:如果是0,就返回父亲说我的高度为0,因为自己没有高度

第二种:非0,那么我得统计完我自己的左和右高度才能告诉父亲的高度

#include<iostream>
using namespace std;
struct tree{
	int data;
	int l,r;
};
tree t[110];
int dfs(int i){
	if(t[i].data==0)return 0;
	int h1 = dfs(t[i].l);
	int h2 = dfs(t[i].r);
	return max(h1,h2)+1;
}
int main(){
	int n;
	cin>>n;
	
	int d,l,r;
	for(int i=1;i<=n;i++){
		cin>>d>>l>>r;
		t[i].data = d;
		t[i].l = l;
		t[i].r = r;	
	}
	
	int height = dfs(1);
	
	cout<<height;
		
	
	return 0;
};

②竞赛题 FBI树(后序数组建树、后序数组输出)

每组输入数据的第一行是一个整数N(0<=N<=10),第二行是一个长度为2N的“01”串。

数据规模:
对于40%的数据,N<=2;
对于全部的数据,N<=10。

输出格式

每组输出包括一行,这一行只包含一个字符串,即FBI树的后序遍历序列。

输入样例 

3
10001011

输出样例 

IBFBBBFIBFIIIFF

注意:size of array 'c' is not an integral constant-expression

char c【N】不能用const int N = ...,来规定长度,数组 'c' 的大小不是整型常量表达式

树的一些性质

1、一颗满二叉树的高度为n,一共有2^n - 1个结点

2、每一层的最左下标就是这一行的元素个数,每一层的最后一个下标就是(最左下标*2-1)

#include<iostream>
using namespace std;
char c[2058];
string s;
int L;
void TreeBuild(int root){
	//倒数第二层开始 
	if(root>=L)return; 
	
	TreeBuild(root*2);
	TreeBuild(root*2+1);
	
	//左右子树键好后父亲开始 
	if(c[root*2]=='B'&&c[root*2+1]=='B')c[root] = 'B'; 
	else if(c[root*2]=='I'&&c[root*2+1]=='I')c[root] = 'I';
	else c[root] = 'F';
	
}
//后序遍历 
void dfs(int root){
	//最后一层开始
	if(root>=2*L)return;
	
	dfs(root*2);
	dfs(root*2+1);
	
	cout<<c[root]; 
	
	
}
int main(){
	int n;
	cin>>n;//2^n长的字符串,然而并没有什么用,这个值
	cin>>s;
	L = s.length(); 
	
	//将字符存储在 len - 2*len - 1当中
	for(int i=0,j=L;i<L;i++,j++){
		if(s[i]=='1')c[j] = 'I';
		else c[j] = 'B';
	} 
	
	//开始建树 
	TreeBuild(1);
	dfs(1);

	return 0;
}

2 链表建树

单独只告诉先序、中序、后序是无法建树的,像本道题由于有#的出现才能确定一颗树

那么可以确定一颗树就是知道:

知道一个中序:左 根 右 + 一个先序或者后序确定根即可

①含‘#’的先序建树、中序输出

1、typedef {}*node;不是node*

2、malloc的c++写法 Node node = new TreeNode()

3、建树的过程中统计叶子节点个数

4、先序建树思路:根、 左 、右 关键点:对于每个根本质上是结点,那么建不建这个结点依据是字符是否为‘#’,树的根肯定是不为‘#’所以不用考虑。

关键点:那么我 根 建完后要返回父亲什么信息呢?

第一种:如果为‘#’直接返回NULL给父亲

第二种:如果非‘#’,我需要继续建好我的子树才能给父亲,所以 left 继续create,right继续create

//利用flag剪枝
//中序遍历:左到根开始回退 中 右到根回退中的上一层 
#include<iostream>
using namespace std;
typedef struct TreeNode{
	char op;
	struct TreeNode *left;
	struct TreeNode *right;
}*Node;
string s;
int i,cnt;
Node InOrder(){
  	char c = s[i++];  
  	if(c=='#'){
  		return NULL;
	}
	Node root = new TreeNode();
	root->op  = c;
	root->left = NULL;
	root->right = NULL;
	root->left = InOrder();
	root->right = InOrder();
	
	if(root->left==NULL&&root->right==NULL){
		cnt++;
	}
	 
	return root;
}
void Midprint(Node head){
	
	if(head->left!=NULL)Midprint(head->left);
	printf("%c",head->op);
	if(head->right!=NULL)Midprint(head->right);
	
}
int main(){
	cin>>s;
	
	//Inorder先序建树的同时统计叶子结点	
	Node root = InOrder();
	
	Midprint(root);
	
	cout<<'\n'<<cnt<<'\n';
	
	return 0;
}

②知道中序和后序建树,先序输出

BADC
BDCA

ABCD

#include<iostream>
using namespace std;
string s1,s2;
void sol(int l1,int r1,int l2,int r2){
	if(l1>r1||l2>r2)return;	
	
	int pos;
	char op = s2[r2];
	for(int i=l1;i<=r1;i++){
		if(s1[i]==op){
			cout<<op;
			pos = i;
			break;
		}
	}
	
	sol(l1,pos-1,l2,l2+pos-l1-1);
	sol(pos+1,r1,l2+pos-l1,r2-1);
	
}
int main(){
	cin>>s1>>s2;
	
	sol(0,s1.length()-1,0,s2.length()-1);
	
	return 0;
}

1 dfs(中序左右,后序左右)

2 在 str1的(l1,r1)中 pos = FInd ( s2 [r2] )

3  先序输出可以cout<< str1[pos],break

4 dfs 左子树的中序左右:( l1, pos-1) ,后序左右(l2 , l2 + pos - l1 - 1)

5 dfs 右子树中序左右(pos + 1,r1),后序左右(l2+pos-l1,r2-1);

6 递归出口条件记住就行

注:传入后序左右的目的是为了确认“根”

③ 知道中序和先序,后序输出

ABEDFCHG
CBADEFGH

注意s从0开始就行,其他和②一样

#include<iostream>
using namespace std;
string s1,s2;
//ABEDFCHG 中 
//CBADEFGH 先  根 左 右 
void sol(int l1,int r1,int l2,int r2){
	if(l1>r1||l2>r2)return;	
	
	//在先序中找到根 
	int pos;
	char op = s2[l2];
	
	//在中序中找到根 
	for(int i=l1;i<=r1;i++){
		if(s1[i]==op){
			pos = i;
			break;
		}
	}
	
	//传入左子树在先序中的左右 
	sol(l1,pos-1,l2+1,l2+(pos - l1));
	
	//传入右子树在先序中的左右 
	sol(pos+1,r1,l2+(pos-l1)+1,r2);
	
	//根输出 
	cout<<s1[pos];
	
}
int main(){
	cin>>s1>>s2;
	
	//传入中序和先序的左右 
	sol(0,s1.length()-1,0,s2.length()-1);
	
	return 0;
}

④知道中序和按层序列,先序输出

#include<iostream>
using namespace std;
string s1,s2;
void sol(int l1,int r1,int l2,int r2){
	if(l1>r1)return;	
	
	int pos;
	int flag = 0;
	//遍历层序在中序中找到根 
	for(int i=l2;i<=r2;i++){
		for(int j=l1;j<=r1;j++){
			if(s1[j]==s2[i]){
				pos = j;
				cout<<s1[j];
				flag = 1; 
				break;
			}
		}
		if(flag==1)break;
	}
	
	//传入左子树在先序中的左右 
	sol(l1,pos-1,l2,r2);
	sol(pos+1,r1,l2,r2);

}
int main(){
	cin>>s1>>s2; 
	sol(0,s1.length()-1,0,s2.length()-1);
	
	return 0;
}

遍历层序所有点 for i l2 - r2

嵌套遍历中序 for j l1 - r1 ,找到s1[j] = s2[i] 那么找到根在中序中的位置 pos = j ;先序输出根cout<<s2[pos];

利用flag两层退出

那么层序的左右怎么在左子树和右子树里面写呢?

首先一定不可能确定中序的左右子树在层序的位置,它是跳跃的。

所以只能死办法全部传入,那么层序中第一个在子树中找到的值就是这颗树的根。

一些关于递归的想法:

如果你的dfs是没有 if条件的 dfs,意味在开头没有出口 if 结束不了

反之,可以不用。如果用了,就是减枝

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值