前缀树里面可以存一堆字符串,也可以说是一堆单词,存完之后我们可以轻松判断一个指定的字符串是否出现过

下面我来详细解释一下实现细节

  1. const int maxnode=*+; //单词个数*每一个单词的字符数
  2. const int sigma_size=;
  3. struct Trie
  4. {
  5. int ch[maxnode][sigma_size];
  6. int val[maxnode];
  7. int sz;
  8. void clear()
  9. {
  10. sz=;
  11. memset(ch[],,sizeof(ch[]));
  12. memset(val,,sizeof(val));
  13. }
  14. int idx(char c)
  15. {
  16. return c-''; //这里根据情况修改
  17. }
  18. };

这里面的结点总数为单词个数和每一个单词最多包含的字符数的乘积。

sigma_size是单词字符的字符集大小,数字就是10,字母就是26

看ch之前我们先来理解一下sz,sz是一个自增变量,是每一个结点的唯一标志,也就是ID

ch[i][j]就表示的是第i个结点是第j种字符表示的(很显然sigma_size作为字符集大小),其值为当前结点在创建时分配的ID,也就是sz

idx这个函数是将字符转化成对应的下标的,也就是前面提到的那个j,第j种字符

每一个结点都可以有一个附加信息,附加什么都可以,但是如果这个结点有意义不要附加0,因为附加0的话表示当前结点没意义(*^▽^*)

那我附加什么好呢,我可以附加这个单词在单词数组中的下标,这样我就能直接根据这个附加信息查到这个单词是啥了不用遍历了

接下来我们介绍插入部分

  1. void insert(const char *s,int v) //v是每一个单词的附加信息,一定不能是0
  2. {
  3. int u=;
  4. int n=strlen(s);
  5. for(int i=;i<n;i++)
  6. {
  7. int c=idx(s[i]);
  8. if(!ch[u][c])
  9. {
  10. memset(ch[sz],,sizeof(ch[sz]));
  11. val[sz]=;
  12. ch[u][c]=sz++;
  13. }
  14. //这里可以加else改为int函数,注意一定要等输入完再break否则运行错
  15. /*
  16. else
  17. {
  18. if(val[ch[u][c]])
  19. return 0;
  20. if(i==n-1)
  21. return 0;
  22. }
  23. */
  24. u=ch[u][c];
  25. }
  26. val[u]=v;
  27. }

插入部分的核心就是根据字符串创建ch并分配sz,到底了之后,给这个结点val赋值表示单词结束。

注释部分可以直接把插入改成有返回值的函数,如果之前这个词插过了就不插入了返回0,这里分两种情况,一种是插入的本身就是一个前缀,一种是之前的单词是这次新插入单词的前缀。

  1. void find_prefixes(const char *s,int len,vector<int>& ans)
  2. {
  3. int u=;
  4. for(int i=;i<len;i++)
  5. {
  6. if(s[i]=='\0')
  7. break;
  8. int c=idx(s[i]);
  9. if(!ch[u][c])
  10. break;
  11. u=ch[u][c];
  12. if(val[u]!=)
  13. ans.push_back(val[u]);
  14. }
  15. }

这个函数会在整个树中找当前前缀的所有单词并把他们的标记存在ans数组里,比如前缀是ai,那么aie,air,aiop等的标记就都找到了,相当于这些单词都找到了。

完整代码如下,实现了一个动态的插入和判断当前插入的单词是否是已经插入的单词前缀的过程(两种情况哦)。

  1. #include<iostream>
  2. #include<cstring>
  3. #include<vector>
  4. using namespace std;
  5. const int maxnode=*+; //单词个数*每一个单词的字符数
  6. const int sigma_size=;
  7. struct Trie
  8. {
  9. int ch[maxnode][sigma_size];
  10. int val[maxnode];
  11. int sz;
  12. void clear()
  13. {
  14. sz=;
  15. memset(ch[],,sizeof(ch[]));
  16. memset(val,,sizeof(val));
  17. }
  18. int idx(char c)
  19. {
  20. return c-''; //这里根据情况修改
  21. }
  22. void insert(const char *s,int v) //v是每一个单词的附加信息,一定不能是0
  23. {
  24. int u=;
  25. int n=strlen(s);
  26. for(int i=;i<n;i++)
  27. {
  28. int c=idx(s[i]);
  29. if(!ch[u][c])
  30. {
  31. memset(ch[sz],,sizeof(ch[sz]));
  32. val[sz]=;
  33. ch[u][c]=sz++;
  34. }
  35. //这里可以加else改为int函数,注意一定要等输入完再break否则运行错
  36. /*
  37. else
  38. {
  39. if(val[ch[u][c]])
  40. return 0;
  41. if(i==n-1)
  42. return 0;
  43. }
  44. */
  45. u=ch[u][c];
  46. }
  47. val[u]=v;
  48. }
  49. void find_prefixes(const char *s,int len,vector<int>& ans)
  50. {
  51. int u=;
  52. for(int i=;i<len;i++)
  53. {
  54. if(s[i]=='\0')
  55. break;
  56. int c=idx(s[i]);
  57. if(!ch[u][c])
  58. break;
  59. u=ch[u][c];
  60. if(val[u]!=)
  61. ans.push_back(val[u]);
  62. }
  63. }
  64. };
  65. const int maxn=;
  66. int n;
  67. Trie trie;
  68. char word[maxn][];
  69. int main()
  70. {
  71. int T;
  72. cin>>T;
  73. while(T--)
  74. {
  75. trie.clear();
  76. int flag=;
  77. cin>>n;
  78. for(int i=;i<n;i++)
  79. {
  80. cin>>word[i];
  81. trie.insert(word[i],i+);
  82. }
  83. vector<int> p;
  84. for(int i=;i<n;i++)
  85. {
  86. p.clear();
  87. trie.find_prefixes(word[i],strlen(word[i])-,p);
  88. if(p.size()!=)
  89. {
  90. flag=;
  91. break;
  92. }
  93. }
  94. if(flag)
  95. cout<<"YES"<<endl;
  96. else
  97. cout<<"NO"<<endl;
  98. }
  99. return ;
  100. }
  1. ch[maxnode][sigma_size]

数据结构&字符串:字典树的更多相关文章

  1. 算法与数据结构基础 - 字典树(Trie)

    Trie基础 Trie字典树又叫前缀树(prefix tree),用以较快速地进行单词或前缀查询,Trie节点结构如下: //208. Implement Trie (Prefix Tree)clas ...

  2. 数据结构 -- Trie字典树

    简介 字典树:又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种. 优点:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高. 性质:   1.  根节 ...

  3. 字符串hash与字典树

    title: 字符串hash与字典树 date: 2018-08-01 22:05:29 tags: acm 算法 字符串 概述 这篇主要是关于字符串里的 字符串hash 和 字符串字典树,,两个都是 ...

  4. python3实现互信息和左右熵的新词发现--基于字典树

    字典树 原来讲明白了剩下的就是具体实现了,最适合存储和计算词频的数据结构就是字典树,这里给一个讲解的很清楚的链接 具体代码 代码已开源,需要的点击这个Github

  5. 数据结构&字符串:01字典树

    利用01字典树查询最大异或值 01字典树的是只含有0和1两种字符的字典树,在使用它的时候,把若干数字转成二进制后插入其中 在查询树中的哪个数字和给定数字有最大异或值的时候,从根开始贪心查询就ok了 H ...

  6. [数据结构]字典树(Tire树)

    概述: Trie是个简单但实用的数据结构,是一种树形结构,是一种哈希树的变种,相邻节点间的边代表一个字符,这样树的每条分支代表一则子串,而树的叶节点则代表完整的字符串.和普通树不同的地方是,相同的字符 ...

  7. Trie树|字典树(字符串排序)

    有时,我们会碰到对字符串的排序,若采用一些经典的排序算法,则时间复杂度一般为O(n*lgn),但若采用Trie树,则时间复杂度仅为O(n). Trie树又名字典树,从字面意思即可理解,这种树的结构像英 ...

  8. NYOJ 163 Phone List (字符串处理 字典树)

    题目链接 描述 Given a list of phone numbers, determine if it is consistent in the sense that no number is ...

  9. 【字符串算法】字典树(Trie树)

    什么是字典树 基本概念 字典树,又称为单词查找树或Tire树,是一种树形结构,它是一种哈希树的变种,用于存储字符串及其相关信息. 基本性质 1.根节点不包含字符,除根节点外的每一个子节点都包含一个字符 ...

  10. I: Carryon的字符串排序(字典树/map映射)

    2297: Carryon的字符串 Time Limit: C/C++ 1 s      Java/Python 3 s      Memory Limit: 128 MB      Accepted ...

随机推荐

  1. 《剑指Offer》题二十一~题三十

    二十一.调整数组顺序使奇数位于偶数前面 题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 测试用例: 功能测试:输入数组中的奇 ...

  2. StrBlobPtr类——weak_ptr访问vector元素

    #include <iostream> #include <memory> #include <string> #include <initializer_l ...

  3. onethink框架显示Access denied for user 'root'@'localhost' (using password: NO)

    本地开发的时候使用的用户名是root,密码为空,它会生成两份.一份在Common/config.php里面,还有一份在Application\User\Conf/config.php 在linux环境 ...

  4. python学习第二天-基本数据类型常用方法

    1.直入主题 python中基本的数据类型有 数字(整形,长整形,浮点型,复数) 字符串 字节串:在介绍字符编码时介绍字节bytes类型 列表 元组 字典 集合 下面我们直接将以下面几个点进行学习 # ...

  5. SFTPHelper

    public class SFTPHelper { #region 字段或属性 private readonly SftpClient _sftp; /// <summary> /// S ...

  6. 不清楚System.Diagnostics.Process.Start(e.LinkText); 的含义

    using System; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms ...

  7. Mysql查询优化从入门到跑路(一)数据库与关系代数

    1.怎样才算是数据库?     ACID,是指在数据库管理系统中事务所具有的四个特性     1)原子性     2)一致性     3)隔离性     4)持久性       关系数据库,基于关系代 ...

  8. KMP算法字符串查找子串

    题目: 经典的KMP算法 分析: 和KMP算法对应的是BF算法,其中BF算法时间复杂度,最坏情况下可以达到O(n*m),而KMP算法的时间复杂度是O(n + m),所以,KMP算法效率高很多. 但是K ...

  9. 第71天:jQuery基本选择器(二)

    jQuery选择器 一.内容过滤选择器 选择器 描 述 返 回 示 例 :contains(text) 匹配含有文本内容text的元素 集合元素 $(“p:contains(今天)”) :empty ...

  10. Javascript-基础2

    1. Javascript 字符串里面的方法: obj.length 长度 obj.trim() 移除空白 obj.trimLeft() obj.trimRight) obj.charAt(n) 返回 ...