二叉树刷一波~

1337:【例3-2】单词查找树


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 1810     通过数: 954

【题目描述】

在进行文法分析的时候,通常需要检测一个单词是否在我们的单词列表里。为了提高查找和定位的速度,通常都画出与单词列表所对应的单词查找树,其特点如下:

1.根结点不包含字母,除根结点外每一个结点都仅包含一个大写英文字母;

2.从根结点到某一结点,路径上经过的字母依次连起来所构成的字母序列,称为该结点对应的单词。单词列表中的每个单词,都是该单词查找树某个结点所对应的单词;

3.在满足上述条件下,该单词查找树的结点数最少。

4.例如图3-2左边的单词列表就对应于右边的单词查找树。注意,对一个确定的单词列表,请统计对应的单词查找树的结点数(包含根结点)。

【输入】

为一个单词列表,每一行仅包含一个单词和一个换行/回车符。每个单词仅由大写的英文字母组成,长度不超过63个字母 。文件总长度不超过32K,至少有一行数据。

【输出】

仅包含一个整数,该整数为单词列表对应的单词查找树的结点数。

【输入样例】

A
AN
ASP
AS
ASC
ASCII
BAS
BASIC

【输出样例】

13

 思路:

首先一波百度:

字典树

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

学习博客:https://www.cnblogs.com/TheRoadToTheGold/p/6290732.html

大致过程是:每个节点代表一个字母,每插入一个单词时,进行一次插入处理。

每个节点都有A-Z共26个孩子,存到节点对应child数组[0-25]

从单词的第1个字母开始遍历:当当前节点对应该字母的child数组为空,给他创建一下,节点数+1

cnt表示前缀出现的次数。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=10015,mod=32767;
struct node{
    int cnt;
    node *child[27];
};
int ans;
node *build(){
    node *k=new node;
    k->cnt=0;
    memset(k->child,0,sizeof(k->child));
    return k;
}

void Insert(node *root,char *s){
    while(*s){
        int id=*s-'A';
        if(root->child[id]==NULL){
            root->child[id]=build();
            ans++;
        }
        root=root->child[id];
        root->cnt++;
        s++;
    }
}

int main(){
    char s[100];
    node *q=build();
    while(scanf("%s",s)!=EOF){
        Insert(q,s);
    }
    printf("%d\n",++ans);
}

1338:【例3-3】医院设置


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 1067     通过数: 756

【题目描述】

设有一棵二叉树(如图3-8,其中圈中的数字表示结点中居民的人口,圈边上数字表示结点编号。现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻结点之间的距离为1。就本图而言,若医院建在1处,则距离和=4+12+2*20+2*40=136;若医院建在3处,则距离和=4*2+13+20+40=81……

【输入】

第一行一个整数n,表示树的结点数(n≤100)。接下来的n行每行描述了一个结点的状况,包含三个整数,整数之间用空格(一个或多个)分隔,其中:第一个数为居民人口数;第二个数为左链接,为0表示无链接;第三个数为右链接,为0表示无链接。

【输出】

一个整数,表示最小距离和。

【输入样例】

5
13 2 3
4 0 0
12 4 5
20 0 0
40 0 0

【输出样例】

81

思路

写了个dfs……

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=115,mod=32767;
int tmp,cnt,a[N],head[N];

struct A{
    int to,nex;
}edge[2*N];

void add(int from,int to){
    edge[cnt].to=to;
    edge[cnt].nex=head[from];
    head[from]=cnt++;
}

void dfs(int now,int dep,int pre){
    tmp+=a[now]*dep;
    for(int i=head[now];i!=-1;i=edge[i].nex){
        int dot=edge[i].to;
        if(dot==pre)continue;
        dfs(dot,dep+1,now);
    }
}

int main(){
    int n,x,y;
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        scanf("%d%d",&x,&y);
        if(x!=0){add(i,x);add(x,i);}
        if(y!=0){add(i,y);add(y,i);}
    }
    int ans=INF;
    for(int i=1;i<=n;i++){
        tmp=0;
        dfs(i,0,0);
        ans=min(ans,tmp);
    }
    printf("%d\n",ans);
}

1340:【例3-5】扩展二叉树


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 905     通过数: 693

【题目描述】

由于先序、中序和后序序列中的任一个都不能唯一确定一棵二叉树,所以对二叉树做如下处理,将二叉树的空结点用·补齐,如图所示。我们把这样处理后的二叉树称为原二叉树的扩展二叉树,扩展二叉树的先序和后序序列能唯一确定其二叉树。

现给出扩展二叉树的先序序列,要求输出其中序和后序序列。

【输入】

扩展二叉树的先序序列。

【输出】

输出其中序和后序序列。

【输入样例】

ABD..EF..G..C..

【输出样例】

DBFEGAC
DFGEBCA

思路:

注意对于扩展二叉树,边读边建树,对于建树的过程,不会结束不了,因为叶子节点的左右子树肯定是空的,输入的最后一个字符肯定是 '.' 这时候就返回NULL

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=10015,mod=32767;
char s[N];
struct node{
    struct node *lc,*rc;
    char elem;
};

node *Create_tree(){
    char ch;
    scanf("%c",&ch);
    if(ch=='.')return NULL;
    node *q=new node;
    q->elem=ch;
    q->lc=Create_tree();
    q->rc=Create_tree();
    return q;
}

void Post_print(node *q){
    if(q!=NULL){
        Post_print(q->lc);
        Post_print(q->rc);
        printf("%c",q->elem);
    }
}
void In_print(node *q){
    if(q!=NULL){
        In_print(q->lc);
        printf("%c",q->elem);
        In_print(q->rc);
    }
}
int main(){
    node *q=Create_tree();
    In_print(q);
    printf("\n");
    Post_print(q);
    printf("\n");
}

1364:二叉树遍历(flist) - 中序,层次推先序


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 860     通过数: 552

【题目描述】

树和二叉树基本上都有先序、中序、后序、按层遍历等遍历顺序,给定中序和其它一种遍历的序列就可以确定一棵二叉树的结构。

假定一棵二叉树一个结点用一个字符描述,现在给出中序和按层遍历的字符串,求该树的先序遍历字符串。

 

【输入】

两行,每行是由字母组成的字符串(一行的每个字符都是唯一的),分别表示二叉树的中序遍历和按层遍历的序列。

【输出】

一行,表示二叉树的先序序列。

【输入样例】

DBEAC
ABCDE

【输出样例】

ABDEC

思路:

每次都要遍历一遍层次遍历的数组,把已经输出的数组用vis标记为1

对于每一个子树,我们用一个范围表示它在中序遍历里的数组下标范围。

然后遍历层序遍历的数组,找到数组里出现的第一个(第一个是根)满足没被输出并且,出现在中序遍历数字的范围里。

这个值作为子树的根。

代码如下:


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=200015,mod=32767;
int vis[N];
char s1[N],s2[N];

void solve(int now,int len1,int len2){
    int i,j;
    for(i=0;i<len2;i++){//从层序遍历里找根节点
        if(vis[i])continue;
        for(j=now;j<len1;j++){
            if(s1[j]==s2[i]){
                printf("%c",s2[i]);
                vis[i]=1;
                break;
            }
        }
        if(vis[i])break;
    }
    if(j>now)solve(now,j,len2);
    if(j+1<len1)solve(j+1,len1,len2);
}

int main(){
    scanf("%s%s",s1,s2);
    solve(0,strlen(s1),strlen(s2));
    printf("\n");
}

1366:二叉树输出(btout)


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 714     通过数: 393

【题目描述】

树的凹入表示法主要用于树的屏幕或打印输出,其表示的基本思想是兄弟间等长,一个结点的长度要不小于其子结点的长度。二叉树也可以这样表示,假设叶结点的长度为1,一个非叶结点的长度等于它的左右子树的长度之和。

一棵二叉树的一个结点用一个字母表示(无重复),输出时从根结点开始:

每行输出若干个结点字符(相同字符的个数等于该结点长度),

如果该结点有左子树就递归输出左子树;

如果该结点有右子树就递归输出右子树。

假定一棵二叉树一个结点用一个字符描述,现在给出先序和中序遍历的字符串,用树的凹入表示法输出该二叉树。

 

【输入】

两行,每行是由字母组成的字符串(一行的每个字符都是唯一的),分别表示二叉树的先序遍历和中序遍历的序列。

【输出】

行数等于该树的结点数,每行的字母相同。

【输入样例】

ABCDEFG
CBDAFEG

【输出样例】

AAAA
BB
C
D
EE
F
G

思路:

知识简单的记录一下节点“长度”

代码如下:



#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=10015,mod=32767;
struct node{
    node *lc,*rc;
    char elem;
    int dep;
};
char s1[N],s2[N];
node *solve(char *pre,char *in,int len){
    if(len==0)return NULL;
    int k=0;
    for(;k<len;k++){
        if(in[k]==*pre)break;
    }
    node *q=new node;
    q->elem=*pre;
    q->lc=solve(pre+1,in,k);
    q->rc=solve(pre+k+1,in+k+1,len-k-1);
    if(q->rc==NULL&&q->lc==NULL)q->dep=1;
    else if(q->lc==NULL)q->dep=q->rc->dep;
    else if(q->rc==NULL)q->dep=q->lc->dep;
    else q->dep=q->lc->dep+q->rc->dep;
    return q;
}
void pre_print(node *q){
    if(q==NULL)return ;
    for(int i=1;i<=q->dep;i++){
        printf("%c",q->elem);
    }
    printf("\n");
    pre_print(q->lc);
    pre_print(q->rc);
}
int main(){
    scanf("%s%s",s1,s2);
    node *q=solve(s1,s2,strlen(s2));
    pre_print(q);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值