• 字典树模板( 指针版 && 数组版 )


    模板 : 

    #include<string.h>
    #include<stdio.h>
    #include<malloc.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn = 26;
    
    struct Trie
    {
        Trie *Next[maxn];
        int v;
        inline void init(){
            this->v = 1;
            for(int i=0; i<maxn; i++)
                this->Next[i] = NULL;
        }
    };
    Trie *root = (Trie *)malloc(sizeof(Trie));
    
    void CreateTrie(char *str)
    {
        int len = strlen(str);
        Trie *p = root, *tmp;
        for(int i=0; i<len; i++){
            int idx = str[i]-'a';
    
            if(p->Next[idx] == NULL){
                tmp = (Trie *)malloc(sizeof(Trie));
                tmp->init();
                p->Next[idx] = tmp;
            }else p->Next[idx]->v++;
    
            p = p->Next[idx];
        }
        p->v = -1;//若为结尾,则将v改成-1,当然字典树里面的变量都是要依据题目
                  //设置并且在特定位置赋值的
    }
    
    int FindTrie(char *str)
    {
        int len = strlen(str);
        Trie *p = root;
        for(int i=0; i<len; i++){
            int idx = str[i]-'a';
            p = p->Next[idx];
            //...进行一系列操作
        }
    }
    
    inline void DelTrie(Trie *T)
    {
        if(T == NULL) return ;
        for(int i=0; i<maxn; i++){
            if(T->Next[i] != NULL)
                DelTrie(T->Next[i]);
        }
        free(T);
        return ;
    }
    
    int main(void)
    {
        root.init();//!!!
        //...
    }
    指针版
    #include<string.h>
    #include<stdio.h>
    #include<malloc.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn = 26 + 1;
    
    struct Trie
    {
        int Next[maxn], v;
        inline void init(){
            v = 1;
            memset(Next, -1, sizeof(Next));
        }
    };
    
    struct Trie Node[1000000]; // 字典树可能最多的节点数,注意开足了!
    
    int tot = 0;
    
    void CreateTrie(char *str)
    {
        int len = strlen(str);
        int now = 0;
        for(int i=0; i<len; i++){
            int idx = str[i]-'a';
            int nxt = Node[now].Next[idx];
            if( nxt == -1){
                nxt = ++tot;
                Node[nxt].init();
                Node[now].Next[idx] = nxt;
            }else Node[nxt].v++;
            now = nxt;
        }
        // Node[now].v = //尾部标志
    }
    
    int FindTrie(char *str)
    {
        int len = strlen(str);
        int now = 0;
        int nxt;
        for(int i=0; i<len; i++){
            int idx = str[i]-'a';
            if(Node[now].Next[idx] != -1) now = Node[now].Next[idx];
            else return 0;
        }
        return Node[now].v;//返回该返回的值
    }
    数组版

     

    字典树算法参考 ==> http://www.cnblogs.com/tanky_woo/archive/2010/09/24/1833717.html

     IOI论文《浅析字母树在信息学竞赛中的应用》 ==> http://www.doc88.com/p-434727490439.html

     

    相关题目 : 

    HUD 1251

    题意 : 给出很多单词(只有小写字母组成,不会有重复的单词出现),要求统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).

    分析 : 模板题,直接累加前缀即可

    ///数组版
    #include<string.h>
    #include<stdio.h>
    #include<malloc.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn = 26 + 1;
    
    struct Trie
    {
        int Next[maxn], v;
        inline void init(){
            v = 1;
            memset(Next, -1, sizeof(Next));
        }
    };
    
    struct Trie Node[1000000]; // 字典树可能最多的节点数,注意开足了!
    
    int tot = 0;
    
    void CreateTrie(char *str)
    {
        int len = strlen(str);
        int now = 0;
        for(int i=0; i<len; i++){
            int idx = str[i]-'a';
            int nxt = Node[now].Next[idx];
            if( nxt == -1){
                nxt = ++tot;
                Node[nxt].init();
                Node[now].Next[idx] = nxt;
            }else Node[nxt].v++;
            now = nxt;
        }
    }
    
    int FindTrie(char *str)
    {
        int len = strlen(str);
        int now = 0;
        int nxt;
        for(int i=0; i<len; i++){
            int idx = str[i]-'a';
            if(Node[now].Next[idx] != -1) now = Node[now].Next[idx];
            else return 0;
        }
        return Node[now].v;
    }
    
    
    char s[11];
    int main(void)
    {
        Node[0].init();
        while(gets(s)){
            if(s[0] == '') break;
            CreateTrie(s);
        }
        while(scanf("%s", s)!=EOF){
            printf("%d
    ",FindTrie(s));
        }
        return 0;
    }
    
    ///指针版
    #include<string.h>
    #include<stdio.h>
    #include<malloc.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn = 26;
    
    struct Trie
    {
        Trie *Next[maxn];
        int v;
        inline void init(){
            this->v = 1;
            for(int i=0; i<maxn; i++)
                this->Next[i] = NULL;
        }
    };
    Trie *root = (Trie *)malloc(sizeof(Trie));
    
    
    inline void CreateTrie(char *str)
    {
        int len = strlen(str);
        Trie *p = root, *tmp;
        for(int i=0; i<len; i++){
            int idx = str[i]-'a';
    
            if(p->Next[idx] == NULL){
                tmp = (Trie *)malloc(sizeof(Trie));
                tmp->init();
                p->Next[idx] = tmp;
            }else p->Next[idx]->v++;
    
            p = p->Next[idx];
        }
        //p->v = -1;
    }
    
    
    
    int FindTrie(char *str)
    {
        int len = strlen(str);
        Trie *p = root;
        for(int i=0; i<len; i++){
            int idx = str[i]-'a';
            if(p->Next[idx] != NULL) p = p->Next[idx];
            else return 0;
        }
        return p->v;
    }
    
    inline void DelTrie(Trie *T)
    {
        if(T == NULL) return ;
        for(int i=0; i<maxn; i++){
            if(T->Next[i] != NULL)
                DelTrie(T->Next[i]);
        }
        free(T);
        return ;
    }
    char s[11];
    int main(void)
    {
        root->init();
        while(gets(s)){
            if(s[0] == '') break;
            CreateTrie(s);
        }
    
        while(scanf("%s", s)!=EOF){
            printf("%d
    ",FindTrie(s));
        }DelTrie(root);
        return 0;
    }
    View Code

     

    HDU 2846

    题意 : 给出 P 个单词和 Q 个询问,对于每一次询问给出询问串是多少个 P 中字符的子串

    分析 : 利用KMP的话可以做,但是复杂度爆炸,可以利用字典树,将 P 个单词的每一个以及其子串全部丢去建树,最后问询串直接去跑字典树查询即可。但是在字典树上权值的累加需要注意,例如 abb 这个串,在分解的时候 b 即属于 bb 也属于 b 那么当问询 b 这个字符串的时候就应该输出 2 吗?很显然不是,对于当前分解的串,我们需要给它加一个 id 来判断当前的字符是否是由同一个串分解而来的,就能避免重复计算。

    #include<string.h>
    #include<stdio.h>
    #include<algorithm>
    #include<malloc.h>
    using namespace std;
    const int maxn = 26;
    
    struct Trie{ Trie *Next[maxn]; int v, who; };
    Trie *root = (Trie *)malloc(sizeof(Trie));
    
    
    
    void CreateTrie(char *str, int who)
    {
        int len = strlen(str);
        root->who = who;
        for(int st=0; st<=len-1; st++){
            Trie *p = root, *tmp;
            for(int i=st; i<len; i++){
                int id = str[i] - 'a';
    
                if(p->Next[id]==NULL){
                    tmp = (Trie *)malloc(sizeof(Trie));
                    tmp->v = 1;
                    tmp->who = who;
                    for(int j=0; j<maxn; j++)
                        tmp->Next[j] = NULL;
    
                    p->Next[id] = tmp;
                    p = p->Next[id];
    
                }else{
                    if(who != p->Next[id]->who) {
                        p->Next[id]->v++;
                        p->Next[id]->who = who;
                    }
                    p = p->Next[id];
                }
            }
        }
    
    }
    
    int ans = 0;
    
    bool TrieFind(int n, char *str) //代码将演示在树上找str的前缀是否存在
    {
        ans = 0;
        int len = strlen(str);
        Trie *p = root;
        for(int i=0; i<len; i++){
            int id = str[i] - 'a';
            if(p->Next[id] != NULL) p = p->Next[id];
            else return false;
        }
        ans = p->v;
        return true;
    }
    
    inline void DelTrie(Trie *T)
    {
        int i;
        if(T == NULL) return ;
        for(int i=0; i<maxn; i++){
            if(T->Next[i] != NULL){
                DelTrie(T->Next[i]);
            }
        }
        free(T);
        return ;
    }
    char str[100];
    int main(void)
    {
        for(int i=0; i<maxn; i++) root->Next[i] = NULL;
        root->who = -1;
        root->v = 0;
        int n, q;
        scanf("%d", &n);
        for(int i=0; i<n; i++){
            scanf("%s", str);
            CreateTrie(str, i);
        }
        scanf("%d", &q);
        for(int i=0; i<q; i++){
            scanf("%s", str);
            if(TrieFind(n, str)) printf("%d
    ", ans);
            else puts("0");
        }
        DelTrie(root);
        return 0;
    }
    View Code
  • 相关阅读:
    LiveData讲解
    Android分区存储相关
    十:存储过程和函数
    九:事务
    八:约束 和分页
    七:常见的数据类型
    六:创建和管理表
    五:SQL常见的函数
    四:SQL基本语句
    二:MYSQL 数据库的安装和常见一些命名
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/7604516.html
Copyright © 2020-2023  润新知