trie tree

Posted shulker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了trie tree相关的知识,希望对你有一定的参考价值。

trie树也叫字典树,前缀树
字典树(Trie)有如下几条性质

  1. 结点不存值,依靠树枝(边)存值
  2. 从根节点到某一处标记点为一个单词
  3. 每个结点到其子节点的边上的值各不相同
  4. 插入和查询复杂度均为O(mn),m为字符串个数,n为字符串平均长度
  5. 树深度由最长字符串决定

依次便可做出trie树的结点结构

struct trie{
    int cnt=0;
    bool word=0;
    trie * son[26]={0};
};

让我们依次价绍这几个成员的含义

  1. cnt 这条边上有几个单词经过,即有多少指定的前缀相同的单词
  2. word 从根节点这个结点是否是一个单词
  3. son[26] 其子节点的地址;

依据其基本性质和结构体成员,写出构造函数如下

void make()
{
 string s;
 cin>>s;
 int lo=s.lenth();
 trie * now=root;
 for(int i=0;i<lo;i++){
   if(now->son[s[i]-‘a‘]) now = now->son[s[i]-‘a‘];
   else {
     now->son[s[i]-‘a‘]=new trie;
     now=now->son[s[i]-‘a‘];
   }
   now->cnt++;
 }
 now->word=1;
}

首先读入一个字符串,得到其长度,并将查询指针调至根节点
这时从字符串第一个字符开始查询该字符是否已经存过
如果存过则将查询指针所在结点的cnt++,并移至该节点,如果未存过,则申请一个新结点连接到相应位置上
直到最后一个结点,将最后一个结点中的word标记改为1

根据trie树性质同时可写出查询函数

void check()
{
    char s[55];
    scanf("%s",s);
    int lo=strlen(s),i;
    trie * now=root;
    for(i=0;i<lo;i++){
        if(now->son[s[i]-‘a‘]){
            now = now->son[s[i]-‘a‘];
            continue;
        }
        else {
            printf("NO
");
            break;
        }
    }
    if(i == lo){
        printf("YES
");
    }
}

首先读入需要查询的字符串,按生成树的方式判断是否存过某字符,若存过,则进入所存结点
若未存过,则break,防止访问空指针,若只判断是否含有某前缀,则上述函数可完成,查询单词时,可将最后一处判断改为

if(i == lo && now->word){
    printf("YES
");
}
else{
    printf("NO
");
}

即当循环结束,字符串在树中时,判断是否这个字符串是整个单词

当树生成时,自动实现字符串的排序
可用递归实现
同时可用递归实现树的删除

与hash比较

Trie 的强大之处就在于它的时间复杂度。O(n),与 Trie 中保存了多少个元素无关。
Hash 表号称是 O(1) 的,但在计算 hash 的时候就肯定会是 O(n) ,而且还有可能冲突的问题
Trie 的缺点是空间消耗很高。

trie树拓展

AC自动机

为trie树上的KMP,留于KMP处详解

后缀树

可实现后缀自动机

基数数

将二进制数拆成几个2位数或几个4位数,按trie树方式存入
好像没什么卵用

trie树例题:

洛谷 2580
题解

#include<cstdio>
#include<cstring>
using namespace std;
struct trie{
    bool check=0;
    bool word=0;
    trie * son[26]={0};
};
trie *root;
void make()
{
    char s[55];
    scanf("%s",s);
    int lo=strlen(s);
    trie * now=root;
    for(int i=0;i<lo;i++){
        if(now->son[s[i]-‘a‘]){
            now = now->son[s[i]-‘a‘];
            continue;
        }
        else {
            now->son[s[i]-‘a‘]=new trie;
            now=now->son[s[i]-‘a‘];
        }
    }
    now->word=1;
}

void check()
{
    char s[55];
    scanf("%s",s);
    int lo=strlen(s),i;
    trie * now=root;
    for(i=0;i<lo;i++){
        if(now->son[s[i]-‘a‘]){
            now = now->son[s[i]-‘a‘];
            continue;
        }
        else {
            printf("WRONG
");
            break;
        }
    }
    if(i == lo && now->word){
        if(now->check){
            printf("REPEAT
");
        }
        else{
            printf("OK
");
            now->check=1;
        }
    }
}

int main()
{
    root = new trie;
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        make();
    }
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        check();
    }
    return 0;
}

codevs 4189
题解:

#include<cstdio>
#include<cstring>
using namespace std;
struct trie{
    trie * son[26];
};
trie *root;
void make()
{
    char s[55];
    scanf("%s",s);
    int lo=strlen(s);
    trie * now=root;
    for(int i=0;i<lo;i++){
        if(now->son[s[i]-‘a‘]){
            now = now->son[s[i]-‘a‘];
            continue;
        }
        else {
            now->son[s[i]-‘a‘]=new trie;
            now=now->son[s[i]-‘a‘];
        }
    }
}

void check()
{
    char s[55];
    scanf("%s",s);
    int lo=strlen(s),i;
    trie * now=root;
    for(i=0;i<lo;i++){
        if(now->son[s[i]-‘a‘]){
            now = now->son[s[i]-‘a‘];
            continue;
        }
        else {
            printf("NO
");
            break;
        }
    }
    if(i == lo){
        printf("YES
");
    }
}

int main()
{
    root = new trie;
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        make();
    }
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        check();
    }
    return 0;
}

hihocoder 1014

#include<cstdio>
#include<cstring>
using namespace std;
struct trie{
    int cnt=0;
    trie * son[26]={0};
};
trie a;
trie *root=&a;
void make()
{
    char s[15];
    scanf("%s",s);
    int lo=strlen(s);
    trie * now=root;
    for(int i=0;i<lo;i++){
        if(now->son[s[i]-‘a‘]){
            now = now->son[s[i]-‘a‘];
            now->cnt++;
            continue;
        }
        else {
            now->son[s[i]-‘a‘]=new trie;
            now=now->son[s[i]-‘a‘];
            now->cnt++;
        }
    }
}
void check()
{
    char s[55];
    scanf("%s",s);
    int lo=strlen(s),i;
    trie * now=root;
    for(i=0;i<lo;i++){
        if(now->son[s[i]-‘a‘]){
            now = now->son[s[i]-‘a‘];
            continue;
        }
        else {
            printf("0
");
            break;
        }
    }
    if(i == lo){
        printf("%d
",now->cnt);
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        make();
    }
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        check();
    }
    return 0;
}












以上是关于trie tree的主要内容,如果未能解决你的问题,请参考以下文章

Implement Trie (Prefix Tree)

Trie (Prefix Tree)前缀树

模板——字典树Trie Tree

trie tree

208. Implement Trie (Prefix Tree)

208. Implement Trie (Prefix Tree)