• Trie(字典树,前缀树)_模板


    Trie

    Trie,又经常叫前缀树,字典树等等。

    Trie,又称前缀树或字典树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,根节点不保存值,这样可以把几个开头不同的串连在一颗Trie上(如abc,efg)。Trie中的键通常是字符串(所以常叫字典树)。

    优点
    可以最大限度地减少无谓的字符串比较,故可以用于词频统计和大量字符串排序。

    缺点
    虽然不同单词共享前缀,但其实trie是一个以空间换时间的算法。其每一个字符都可能包含至多字符集大小数目的指针。

    建树
    两种建法:
    (1) 多叉树:仅字母:26或52,各种字母,数字,符号组合:根据情况算吧,反正需要的空间贼大
    (2) 兄弟儿子表示法:用链表,如链式前向星(个人比较喜欢),遍历时间较上一种长

    应用
    (1)字符串检索
    (2)用多叉树建的树可以实现字典序排序
    (3)最长公共前缀
    (4)AC自动机等会用到

    促使我学习Trie的题目:UVA 11732 "strcmp()" Anyone?

    并没有UVA链接,其他OJ大概也搜得到

    这道题给出一个 strcmp() 函数的实现方式,我们要求的就是判断 ‘==’ 的次数

    int strcmp(char *s, char *t)
    {
        int i;
        for (i = 0; s[i] == t[i]; i++)
            if (s[i] == 0) return 0;
        return s[i] - t[i];
    }
    题面

    由于要比较最后的 0,那么字符串相等则答案加 2 * strlen(str) + 2,否则加 2 * ptr + 1,ptr为中断位置。

    代码
    我使用的是兄弟儿子表示法(很显然),时间复杂度的话,不是很慢,还行吧 . . .

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #define CL(X,N) memset((X), (N), sizeof(X))
     5 using namespace std;
     6 typedef long long LL;
     7 const int maxl = 1e3 + 10, maxn = 4e3 + 10;
     8 int n;
     9 char str[maxl];
    10 int son[maxn * maxl], bro[maxn * maxl], cnt[maxn * maxl];
    11 char trie[maxn * maxl];
    12 LL size = 0, ans = 0;
    13 
    14 inline void Insert(char *s, int len) {
    15     int ptr, cur = 0;
    16     for(int i = 0; i <= len; ++i) {
    17         for(ptr = son[cur]; ptr; ptr = bro[ptr])
    18             if(trie[ptr] == s[i]) break;
    19         if(!ptr) {
    20             ptr = size++;
    21             trie[ptr] = s[i];
    22             bro[ptr] = son[cur];
    23             son[cur] = ptr;
    24             cnt[ptr] = 0;
    25             son[ptr] = 0;
    26         }
    27         ans += (cnt[cur] - cnt[ptr]) * (2 * i + 1);
    28         if(i == len) {
    29             ans += cnt[ptr] * (2 * i + 2);
    30             ++cnt[ptr];
    31         }
    32         ++cnt[cur];
    33         cur = ptr;
    34     }
    35     return ;
    36 }
    37 
    38 inline void Initialize(void) {
    39     son[0] = bro[0] = cnt[0] = 0;
    40     ans = 0;
    41     size = 1;
    42     return ;
    43 }
    44 
    45 int main(int argc, char **argv) {
    46 #ifdef LOCAL
    47     freopen("in.txt", "r", stdin);
    48 #endif
    49     int len, cas = 0;
    50     while(~scanf("%d", &n) && n) {
    51         Initialize();
    52         for(int i = 0; i < n; ++i) {
    53             scanf("%s", str);
    54             len = strlen(str);
    55             Insert(str, len);
    56         }
    57         printf("Case %d: %lld", ++cas, ans);
    58         putchar(10);
    59     }
    60     return 0;
    61 }
    View Code
  • 相关阅读:
    09、Vue.js 3 —— 事件处理
    03、Vue.js 3 —— 模板语法
    vagrant 的介绍与使用
    Asp.Net Core 中的Swagger中间件
    chkconfig和systemd服务管理工具 init.d
    02、Vue.js 3 —— app应用 与 vm组件实例
    01、vue.js 3 笔记(只是本人笔记,大家请自行到官网看文档)
    Linux中的 打包、解压缩 命令(无废话)
    07、Vue.js 3 —— 条件渲染
    0x05、设计模式原则 —— 开闭原则
  • 原文地址:https://www.cnblogs.com/normaldisk/p/9748565.html
Copyright © 2020-2023  润新知