字典树例题介绍:ZOJ 1109 Language of FatMouse,HDOJ 1075hdoj What Are You Talking About

本文深入探讨了字典树在翻译应用中的实现与优化,包括简单的单词翻译与复杂输入符号的处理。通过代码示例展示了如何构建字典树,并实现了排序与二分查找的高效解决方案。此外,文章还提供了使用结构体数组和排序函数进行快速定位的另一种方法,旨在提升搜索效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于字典树,相信还是比较好理解的吧,就是将一次输入中的一些单词,字符串建立成字典。将这些字符每一层存放一个字符,顺序往下查找,在该个字符串(找完该字符串的最后一个字符,即最后一个节点)末尾设置一个节点(一般是存放的东西,比如要翻译过来的单词啊什么的)。

下面来分享两道典型的字典树题:

1.ZOJ 1109 Language of FatMouse:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1109

大概题意:FatMouse只会说鼠语,但是为了迎接WTO的热潮,它想学好英语,所以就搞了个类似小抄的东西。输入英语语言和鼠语,要求我们将鼠语言翻译英语输出。

这是单词的翻译,属于简单的字典树。只要将鼠语见成字典树,对应的英语单词作为节点放在鼠语结束的末尾,每次翻译是查找字典树即可。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
using namespace std;

char fwords[11];
struct Trie{
    Trie *next[26];     //建树,每一层都有26个小写的英文单词(管它用不用呢,万一要全用),如果加入大写和数字,那就要开的更大了
    char eword[11];     //用来储存英语(要存在节点出的,同样,管他用不用呢。

    Trie(){             //树的初始化
        for(int i=0;i<26;i++)
            next[i]=NULL;
        eword[0]='\0';
    }
};
Trie root;                          //这里是树根,从此开始往下建树
void build(char ew[],char d[]){     //d是鼠语
    Trie *now=&root;                //每次建树都要从树根开始,看看初始鼠语字符是否存在
    int len=strlen(d);
    for(int i=0;i<len;i++){
        if(now->next[d[i]-'a']==NULL)   //如果没有,那就新往下建一个
            now->next[d[i]-'a']=new Trie;
        now=now->next[d[i]-'a'];        //有那就顺着这个节点往下摸
    }
    strcpy(now->eword,ew);
}
char *TrieSearch(char str[]){
    Trie *p=&root;
    int len=strlen(str);
    int i;
    for(i=0;i<len&&p->next[str[i]-'a']!=NULL;i++)
        p=p->next[str[i]-'a'];
    if(i==len&&strlen(p->eword)!=0)
        return p->eword;
    return NULL;

}
int main()
{
    char re[11],dic[11];
    char line[30];
    while(gets(line)){
        if(strlen(line) == 0)break;
        sscanf(line,"%s%s",re,dic);
        build(re,dic);
    }
    while(gets(line)){
        char *p=TrieSearch(line);
        if(p) printf("%s\n",p);
        else printf("eh\n");
    }
    return 0;
}

接下来是个稍微变化了一下的字典树题目:

DHOJ 1075hdoj What Are You Talking About:http://acm.hdu.edu.cn/showproblem.php?pid=1075

题意:同样也是要翻译,但是这次输入有其他的各种符号,但是不用管它,最后的时候处理就好了,给出代码:

//Trie
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <cctype>

char tmp[3000+10];  //后续输入
//树的结构体
struct Trie{
    char ewards[11];
    Trie *next[26];
    Trie(){
        for(int i=0;i<26;i++)
            next[i]=NULL;
        ewards[0]='\0';
    }
};
Trie root;          //建立字典树树根
//函数功能:建树并保存单词(即在单词结束时保存节点)
void build(char e[],char mar[]){
    Trie *now=&root;            //从树顶端开始建立
    int len=strlen(mar);
    for(int i=0;i<len;i++){     //mar是字典,直到将其全部非'\0'字符历遍
        if(now->next[mar[i]-'a']==NULL)
            now->next[mar[i]-'a']=new Trie;//如果该字符未被保存过,那么建立新的节点
        now=now->next[mar[i]-'a'];
    }
    strcpy(now->ewards,e);
}

char *TrieSearch(char s[]){
    Trie *p =&root;
    int i;          // 下边还会用到
    for(i=0;s[i]!='\0'&&p->next[s[i]-'a']!=NULL;i++)
        p=p->next[s[i]-'a'];            //符合要求那么就继续向下
    if(s[i]=='\0'&&strlen(p->ewards)!=0)//s被历遍,且最后一个树点有节点标记(此处为有单词
        return p->ewards;
    return NULL;
}

using namespace std;

int main()
{
    char ear[11],mar[11];
    scanf("%s",ear);
    while(scanf("%s",ear)&&ear[0]!='E'){
        scanf("%s",mar);
        build(ear,mar);
    }
    scanf("%s",mar);scanf("\n");    //输入START,记得吞'\n'
    memset(tmp,'\0',sizeof(tmp));
    while(gets(tmp)!=NULL&&tmp[0]!='E'){
        int len=strlen(tmp);
        tmp[len]=' ';len++;
        char tp[3000+10];
        for(int i=0,k=0;i<len;i++){
            if(tmp[i]>='a'||tmp[i]<='z'){
                tp[k]='\0';
                char *temp=TrieSearch(tp);
                if(temp) printf("%s",temp);
                else printf("%s",tp);
                k=0;                    //从新开始保存单词或者结束
                if(i!=len-1) printf("%c",tmp[i]);
            }
            else
                tp[k++]=tmp[i];
        }
        printf("\n");
    }
    return 0;
}

不难发现,字典树对于内存上的消耗还是很大的,下面给出第一题的另一种解法,研究qsort的结构体字符串排序想了好久,再利用二分,时间上就满足了。但是这种方法有些题目还是有些不适用的。我也没想清楚。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100000+10
using namespace std;

struct words{
    char ewords[11];
    char ftword[11];
}arr[MAXN];

int cmp(const void *a,const void *b){
    struct words *pa = (struct words *)a;
    struct words *pb = (struct words *)b;
    return strcmp(pa->ftword,pb->ftword);
}
char * dsearch(char id[],int low,int high){ // 排序后进行二分查找,快速定位下来
    while(low<=high){
        int mid=(low+high)>>1;
        //cout << "str1="<< id <<" str2="<<arr[mid].ftword<<endl;
        if(!strcmp(id,arr[mid].ftword)){
            return arr[mid].ewords;
        }
        else if(strcmp(id,arr[mid].ftword)>0)
            low=mid+1;
        else
            high=mid-1;
    }
    return NULL;

}
int main(){
    int m=0;
    char line[30];
    for(m=0;gets(line)&&strlen(line);m++){
        sscanf(line,"%s%s",arr[m].ewords,arr[m].ftword);
    }
    qsort(arr,m,sizeof(arr[0]),cmp);
    while(gets(line)&&strlen(line)){
        char *p=dsearch(line,0,m);
        if(p) printf("%s\n",p);
        else printf("eh\n");
    }
    return 0;
}

最后,还请大家知道怎么用sort排结构体字符串的指教指教,感谢阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值