zoukankan      html  css  js  c++  java
  • 字典树模板( 指针版 && 数组版 )

    模板 : 

    #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
  • 相关阅读:
    MIne FirstBlog
    P6563 [SBCOI2020]一直在你身旁
    P6563 [SBCOI2020]一直在你身旁
    T122085 [SBCOI2020]时光的流逝
    LC 918. Maximum Sum Circular Subarray
    1026 Table Tennis
    LC 1442. Count Triplets That Can Form Two Arrays of Equal XOR
    LC 1316. Distinct Echo Substrings
    LC 493. Reverse Pairs
    1029 Median (二分)
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/7604516.html
Copyright © 2011-2022 走看看