二叉树系列题目

二叉树系列题目

1.利用二叉树性质解题.

UVA 679 - Dropping Balls

有一棵二叉树,最大深度为D,且所有叶子的深度都相同。所有结点从上到下从左到右 编号为1, 2, 3,…, 2D-1。在结点1处放一个小球,它会往下落。每个内结点上都有一个开关, 初始全部关闭,当每次有小球落到一个开关上时,状态都会改变。当小球到达一个内结点 时,如果该结点上的开关关闭,则往左走,否则往右走,直到走到叶子结点,如图6-2所示。
在这里插入图片描述
一些小球从结点1处依次开始下落,最后一个小球将会落到哪里呢?输入叶子深度D和 小球个数I,输出第I个小球最后所在的叶子编号。假设I不超过整棵树的叶子个数。D≤20。 输入最多包含1000组数据。

方法1:模拟但会TLE,对 I 个球进行模拟下落,到落到某一结点就开关变换.数据较大时会有 2^20 * 20
方法2:利用奇偶性+递归思想.对前两个进行分析:第一个往左,第二个显然往右. 分析可得 如果 I 为 偶数 则最后一个球为往右走的 第 I/2个 ,反之为 往左走的 第(I+1) /2 。
然后再将当前结点作为根.继续判断是往左还是往右.

模拟TLE代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int vis[N];
int main(){
	int t;
	cin>>t;
	while(t--){
		memset(vis,0,sizeof vis);
		int d,n,k=1;
		cin>>d>>n;
		while(n--){
			k=1;
			for(int i=1;i<d;i++)
			{
				vis[k]=!vis[k]; //当球到某个点 该点开关改变.如果此时是开说明之前是关则往左走,反之往右走. 
				k = vis[k]?2*k:2*k+1;
			}
		}
		cout<<k<<endl;
	}
	return 0;
}

AC代码

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		int d,n,k=1;
		cin>>d>>n;
		d--;
		while(d--){
			if(n&1) k*=2,n=(n+1)/2;
			else k=k*2+1,n>>=1; 
		}
		cout<<k<<endl;
	}
	return 0;
} 

总结:本题是一棵完全二叉树.利用了根结点(从1开始编号 )的左儿子为 2n ,右儿子为 2n+1 这一性质。加上奇偶性分析得出规律大大减少时间。另外从0开始编号的完全二叉树 左儿子为 2n+1 ,右儿子为 2n +2

二叉树的遍历.

这里主要有BFS和DFS.我们来主要来谈谈DFS.

DFS:分为三种:先序,后序,中序遍历。先序顺序:根左右。后序顺序:左右根。中序顺序:左根右
相关的性质:已知先序和中序可以确定一棵树。已知后序和中序也可以确定一棵树。但是已知先序和后序不一定能确定一棵树。下面上几个题目。

题型1:给两段字符串,分别为中序和先序,或者分别为中序和后序。让你打印后序(先序)。
主要思想:已知先序或后序可以确定根的位置。然后在中序中找到根的位置。根的左边即为左子树,右边为右子树。
再分别对左右子树进行递归搜索。即可以得到结果。下面上代码。

已知中序和先序,求后序

#include<bits/stdc++.h>
using namespace std;
void dfs(string a,string b){//a:中序字符串 b:先序字符串. 
	if(a.size()>0)
	{
		char c=b[0];//根 
		int k=a.find(c);//根在中序的位置. 
		dfs(a.substr(0,k),b.substr(1,k)); //递归搜索左子树 
		dfs(a.substr(k+1),b.substr(k+1,a.size()-k-1));//递归搜索右子树 
		cout<<c; //最后打印根.  满足左右根的顺序 即为后序遍历. 
	}
}
int main(){  //求后序. 
	string a,b;
	cin>>a>>b;
	dfs(a,b);
	return 0;
} 

已知中序和后序,求先序

#include<iostream>
#include<string>
using namespace std;
void dfs(string a,string b){//a:中序字符串 b:后序字符串 
	 if(a.size()>0) //当子树存在时. 
	 {
	 	char c=b[b.size()-1]; //根为后序的最后位置 
		cout<<c;//先输出根 
		int pos=a.find(c);//根在中序的位置  pos也是左子树的结点数. 
		dfs(a.substr(0,pos),b.substr(0,pos));//dfs 左子树 
		dfs(a.substr(pos+1),b.substr(pos,a.size()-pos-1));	// dfs 右子树 
	 }  //满足根左右的顺序. 
}
int main(){
	string a,b;
	cin>>a>>b;
	dfs(a,b);
	return 0;
}
发布了18 篇原创文章 · 获赞 14 · 访问量 360

猜你喜欢

转载自blog.csdn.net/weixin_45750972/article/details/104968107