码迷,mamicode.com
首页 > 其他好文 > 详细

trie tree

时间:2018-08-13 20:56:29      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:ret   char s   长度   https   scanf   排序   tps   时间复杂度   删除   

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\n");
            break;
        }
    }
    if(i == lo){
        printf("YES\n");
    }
}

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

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

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

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

与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\n");
            break;
        }
    }
    if(i == lo && now->word){
        if(now->check){
            printf("REPEAT\n");
        }
        else{
            printf("OK\n");
            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\n");
            break;
        }
    }
    if(i == lo){
        printf("YES\n");
    }
}

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\n");
            break;
        }
    }
    if(i == lo){
        printf("%d\n",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

标签:ret   char s   长度   https   scanf   排序   tps   时间复杂度   删除   

原文地址:https://www.cnblogs.com/shulker/p/9470502.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!