树和二叉树例题

文章介绍了二叉树的基本操作,如求先序排列的方法,使用substr函数处理字符串,以及构建新二叉树(前序遍历)和堆数据结构的应用。还包括合并果子问题和计算中位数的高效算法,展示了C++编程解决这些IT技术问题的实例。
摘要由CSDN通过智能技术生成

目录

二叉树基本操作

求先序排列

 substr函数

新二叉树 

 堆

合并果子

 中位数


二叉树基本操作

http://t.csdn.cn/knmLO

求先序排列

Description

给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,且二叉树的节点个数 ≤8≤8)。

Input

共两行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。

Output

共一行一个字符串,表示一棵二叉树的先序。

Sample 1

InputcopyOutputcopy
BADC
BDCA
ABCD

#include<cstdio>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
void bef(string mid,string aft){
	if(mid.size()>0){
		char c=aft[aft.size()-1];cout<<c;//二叉树的根 
		int k=mid.find(c);//结点,从此分为左右 
		bef(mid.substr(0,k),aft.substr(0,k));//leftson 
		bef(mid.substr(k+1),aft.substr(k,mid.size()-k-1));//rightson
//s.substr(pos, len)pos到len个字符的拷贝,不加参数会默认拷贝整个s
	}
}
int main(){
	string mid,aft;
	cin>>mid>>aft;
	bef(mid,aft);cout<<endl;
	return 0;
}

 substr函数

substr(size_type _Off = 0,size_type _Count = npos)
形式 : s.substr(pos, len)
返回值: string,包含s中从pos开始的len个字符的拷贝(pos的默认值是0,len的默认值是s.size() - pos,即不加参数会默认拷贝整个s)
异常 :若pos的值超过了string的大小,则substr函数会抛出一个out_of_range异常;若pos+n的值超过了string的大小,则substr会调整n的值,只拷贝到string的末尾

C++中substr()函数用法详解_c++ substr_哦啦哦啦!的博客-CSDN博客

新二叉树 

Description

输入一串二叉树,输出其前序遍历。

Input

第一行为二叉树的节点数 n。(1≤n≤26)

后面 �n 行,每一个字母为节点,后两个字母分别为其左右儿子。特别地,数据保证第一行读入的节点必为根节点。

空节点用 * 表示

Output

二叉树的前序遍历。

Sample 1

InputcopyOutputcopy
6
abc
bdi
cj*
d**
i**
j**
abdicj


#include<cstdio>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
struct node{
	char l,r;
}t[130];//以字符的ACSII码作下标 所以数组开大点
void after(char s){
	if(s=='*')return; 
	cout<<s;
	after(t[s].l );//找leftson的先递归完
	after(t[s].r );//再找rightson
}
int main(){
	int n;cin>>n; 
	char s,c;
	cin>>s;
	cin>>t[s].l;
	cin>>t[s].r;
	for(int i=1;i<n;i++){
		cin>>c;
		cin>>t[c].l ;
		cin>>t[c].r ;
	}
	after(s);
	return 0;
}

FBI树

Description

我们可以把由 0 和 1 组成的字符串分为三类:全 0 串称为 B 串,全 1 串称为 I 串,既含 0 又含 1 的串则称为 F 串。

FBI 树是一种二叉树,它的结点类型也包括 F 结点,B 结点和 I 结点三种。由一个长度为 2N 的 01 串 S 可以构造出一棵 FBI 树 T,递归的构造方法如下:

  1. T 的根结点为 R,其类型与串 S 的类型相同;
  2. 若串 S 的长度大于 1,将串 S 从中间分开,分为等长的左右子串 S1​ 和 S2​;由左子串 S1​ 构造 R 的左子树 T1​,由右子串 S2​ 构造 R 的右子树 T2​。

现在给定一个长度为 2^N 的 01 串,请用上述构造方法构造出一棵 FBI 树,并输出它的后序遍历序列。

Input

第一行是一个整数 N(0≤N≤10),

第二行是一个长度为 2N 的 01 串。

Output

一个字符串,即 FBI 树的后序遍历序列。

Sample 1

InputcopyOutputcopy
3
10001011
IBFBBBFIBFIIIFF
#include<stdio.h>
char A[1025];
void work(int low, int up)
{
    int mid = (low+up)/2;
    if (low!=up){//分成左右长度相同两子串
        work(low, mid);
        work(mid+1,up);
    }//递归出口左右相等 到达树根 
    int i,a=0,b=0;
    for (i=low;i<=up;i++)
        if (A[i]=='0') a++;
        else b++;//全1 
    if (a&&b) printf("F");//有1有0 F
    else if (a) printf("B");//全0 B
    else printf("I");//全1 I
}
int main()
{
    int n;
    scanf("%d", &n);
    scanf("%s", A+1);//从 A[1] 开始输入
    work(1, 1<<n);//1的二进制从右向左移动n位 即为2的n次方
    return 0;
}

 堆

Description

给定一个数列,初始为空,请支持下面三种操作:

  1. 给定一个整数 x,请将 x 加入到数列中。
  2. 输出数列中最小的数。
  3. 删除数列中最小的数(如果有多个数最小,只删除 1 个)。

Input

第一行是一个整数,表示操作的次数 n。
接下来 n 行,每行表示一次操作。每行首先有一个整数 op 表示操作类型。

  • 若 op=1,则后面有一个整数 x,表示要将 x 加入数列。
  • 若 op=2,则表示要求输出数列中的最小数。
  • 若 op=3,则表示删除数列中的最小数。如果有多个数最小,只删除 1 个。

Output

对于每个操作 22,输出一行一个整数表示答案。

Sample 1

InputcopyOutputcopy
5
1 2
1 5
2
3
2
2
5

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int h[N];
int len=0;
void push(int x){ //插入数字
	h[++len]=x;
	int i=len; //重新排序
	while(i>1&&h[i]<h[i/2]){
		swap(h[i],h[i/2]);
		i/=2;//上浮  
	}
}
void pop(){ //删除数字
	h[1]=h[len];
	len--;
	int i=1;
	while(2*i<=len){
		int s=2*i;
		if(s<len&&h[s+1]<h[s]){
			s++;
		}
		if(h[s]<h[i]){
			swap(h[s],h[i]);
			i=s;
		}
		else {
			break;
		}
	}
}
int main(){
	int n;cin>>n;
	int op,x;
	while(n--){
		cin>>op;
		if(op==1){
			cin>>x;
			push(x);
		}
		else if(op==2){
			cout<<h[1]<<endl;//数组经过我们的排列,小数上浮,只要输出h[1]即可
		}
		else{
			pop();
		}
	}
}

合并果子

Description

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。

每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。

因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

例如有 33 种果子,数目依次为 1 , 2 , 9 。可以先将 1 、 2 堆合并,新堆数目为 3 ,耗费体力为 33 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为 12 。所以多多总共耗费体力 3+12=15 。可以证明 1515 为最小的体力耗费值。

Input

共两行。
第一行是一个整数 n(1≤n≤10000) ,表示果子的种类数。

第二行包含 n 个整数,用空格分隔,第 i 个整数 ai​(1≤ai​≤20000) 是第 i 种果子的数目。

Output

一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 231 。

Sample 1

InputcopyOutputcopy
3 
1 2 9 
15

#include<cstdio>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
int n,x;
int sum;
priority_queue<int,vector<int>,greater<int> >q;//自动从大到小排序
int main(){
	ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=0;i<n;i++){
    	cin>>x;
    	q.push(x);//插入队列
	}
	while(q.size()>=2){
		int a,b;
		a=q.top();q.pop();
		b=q.top();q.pop();
		q.push(a+b); //合并至一个
		sum+=a+b;
	}
	cout<<sum<<endl;//总耗费体力
	return 0;
}

 中位数

Description

给定一个长度为 N 的非负整数序列 A,对于前奇数项求中位数。

Input

第一行一个正整数 N。

第二行 N 个正整数 A1…N​。

Output

共 ⌊2N+1​⌋ 行,第 i 行为 A1…2i−1​ 的中位数。

Sample 1

InputcopyOutputcopy
7
1 3 5 7 9 11 6
1
3
5
6

Sample 2

InputcopyOutputcopy
7
3 1 5 9 8 7 6
3
3
5
6

HINT

直接用排序会时间超限,用优先队列存两组数,一组比现中位数大,一组比现中位数小。 


#include<cstdio>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
int a[N];
int n,mid;
priority_queue<int,vector<int> > q1;//大根堆
priority_queue<int,vector<int>,greater<int>  > q2;//小根堆
int main(){
    cin>>n;
    scanf("%d",&a[1]);
    mid=a[1];
    cout<<mid<<endl;
    for(int i=2;i<=n;i++){
        scanf("%d",&a[i]);
        if(a[i]>mid) q2.push(a[i]);
        else q1.push(a[i]);
        if(i%2==1){//奇数
            while(q1.size()!=q2.size()){
                if(q1.size()>q2.size()){
                    q2.push(mid);
                    mid=q1.top();
                    q1.pop();
                }
                else{
                    q1.push(mid);
                    mid=q2.top();
                    q2.pop();
                }
            }
            cout<<mid<<endl;
        }
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值