数据结构~trie树(字典树)

1、概述

Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树。

我理解字典树是看了这位大佬博客。还不了解字典树的可以先进去学习一下

https://www.cnblogs.com/TheRoadToTheGold/p/6290732.html

还有这个讲了下为什么用字典树,和其他的相比优缺点在哪

https://www.cnblogs.com/Allen-rg/p/7128518.html

现在来个题来更进一步了解字典树吧 ,嘻嘻-_-

POJ - 2503  Babelfish

You have just moved from Waterloo to a big city. The people here speak an incomprehensible dialect of a foreign language. Fortunately, you have a dictionary to help you understand them.

Input

Input consists of up to 100,000 dictionary entries, followed by a blank line, followed by a message of up to 100,000 words. Each dictionary entry is a line containing an English word, followed by a space and a foreign language word. No foreign word appears more than once in the dictionary. The message is a sequence of words in the foreign language, one word on each line. Each word in the input is a sequence of at most 10 lowercase letters.

Output

扫描二维码关注公众号,回复: 2265349 查看本文章
Output is the message translated to English, one word per line. Foreign words not in the dictionary should be translated as "eh".

Sample Input

dog ogday
cat atcay
pig igpay
froot ootfray
loops oopslay

atcay
ittenkay
oopslay

Sample Output

cat
eh
loops

Hint

Huge input and output,scanf and printf are recommended. 
 
题意:前面有个字典列表,后一个单词映射到前一个,后面有很多次查询,输出单词映射到的那个单词,如果没有输出eh
思路:因为这题数据比较弱,所以用map映射照样可以过,在这里我们当是字典树入门,之前我们用map可以算某个单词映射到哪个单词,这个字典树和map其实
相差不大,但是在求某个前缀的个数的时候,map就要使用多个映射,这个时候字典树的优势就来了
我们可以看下代码
#include<cstdio>
#include<cstring>
using namespace std;
int top=0;
int a[1000001][27];
int sum[1000001];
void insert(char str[])
{
    int root=0;
    for(int i=0;str[i]!='\0';i++)
    {
        int x=str[i]-'a';
        if(!a[root][x])
        {
            a[root][x]=++top;
        }
        sum[a[root][x]]++;
        root=a[root][x];
    }
}
int find(char str[])
{
    int root=0;
    for(int i=0;str[i]!='\0';i++)
    {
        int x=str[i]-'a';
        if(!a[root][x]) return 0;
        root=a[root][x];
    }
    return sum[root];
}
int main()
{
    char str[11];
    while(gets(str)!=NULL)
    {
        if(strlen(str)==0)
        break;
        insert(str);
    }
    while(gets(str)!=NULL)
    {
        printf("%d\n",find(str));
    }
}

解释:字典树的一些编号什么的解释在上两篇博客中都有讲到,我这里就不再解释,在以上代码中,我们是使用a数组存放字典树,sum数组存放了每个点节点的时候的儿子数量,也就是以这个节点下的大分支的数量个数,这样的话,sum的功能我们就能理解啦,就是sum[k]  ,以1编号到k编号的这个字符串,sum[k]存放的就是这个字符串的一些东西,以上代码中我们存的是儿子数,所以就是以这个字符串为前缀的数量,这里我们就能想到这个sum数组不止可以存放前缀儿子数,下面讲另外一个应用,也就是上面这个题

思路:之前我们sum数组我们存的是到这个编号为止的字符串的儿子数,而这个题是说到一个字符串到另外一个字符串的映射,我们就可以想到,一个是一个字符串对应一个整数,一个是一个字符串对应一个字符串,我们是不是只要把那个sum[k]的整数换成字符串就可以了呢,答案是肯定的,当然我这里是预先把那些字符串存了下来,然后sum[k]存的是对应于那个字符串数组的一个编号,下面看代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<string>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
int n,m,top=0;
int sum[100001];
char str[101],s[11];
char c[100001][27];
char dic[100001][11];
void insert(char str[],int cnt)
{
    int root=0;
    for(int i=0;str[i]!='\0';i++)
    {
        int x=str[i]-'a';
        if(!c[root][x]) c[root][x]=++top;
        root=c[root][x];
    }
    sum[root]=cnt;
}
int find(char str[])
{
    int root=0;
    for(int i=0;str[i]!='\0';i++)
    {
        int x=str[i]-'a';
        if(!c[root][x]) return 0;
        root=c[root][x];
    }
    return sum[root];
}
int main()
{
    int cnt=1;
    while(gets(str)!=NULL)
    {
        if(strlen(str)==0) break;
        sscanf(str,"%s %s",dic[cnt++],s);
        insert(s,cnt-1);
    }
    while(gets(str)!=NULL)
    {
        int x=find(str);
        if(x==0) printf("eh\n");
        else printf("%s\n",dic[x]);
    }
}

字典树可能还有好多骚操作没学,以后学了之后再更新,23333,^_^

猜你喜欢

转载自www.cnblogs.com/Lis-/p/9340699.html