这是C++算法基础-数据结构专栏的第二十七篇文章,专栏详情请见此处。
引入
Trie树,即字典树,顾名思义,就是用类似字典的方式存储数据,而Trie树最经典也是最简单的一个应用就是字符串统计问题。
字符串统计问题就是维护一个字符串集合,并支持两种操作:向集合中插入一个字符串和询问一个字符串在集合中出现了多少次。
下面我们就来讲Trie树之字符串统计问题的实现。
定义
Trie树,即字典树,顾名思义,就是用类似字典的方式存储数据,它是AC自动机的主要组成部分,它的最经典应用是字符串统计问题和最大异或对问题。
过程
例题
题目大意:维护一个字符串集合,并支持两种操作:向集合中插入一个字符串和询问一个字符串在集合中出现了多少次。
算法
对于Trie树,每道题会有相对应的一种存储方式,而在这一题中,我们建立一棵树,用点来代表字母,而从根结点到树上某一结点的路径就代表了一个字符串。
具体来说,我们定义一个数组存储树中每个节点的子节点,其中数组的一维表示节点的编号,二维的数字代表了这条边在字母表中的次序(例如表示号节点连接了字符的节点编号);然后,为了方便识别Trie树中每个字符串的结尾处,我们在相应的节点打上标记并累计,所以我们开一个数组;最后,还需要一个变量,以便于分配新的节点编号。
然后,我们实现两个函数:insert(),向集合中插入一个字符串和query(),询问一个字符串在集合中出现了多少次。
insert()函数的实现很简单:遍历字符串,若当前字符不存在,我们就新建一个节点并分配编号,直到遍历结束,我们在字符串末尾打上标记。
query()函数的实现和insert()函数大体相同:遍历字符串,若当前字符不存在,就直接退出寻找,返回,最后若没有退出寻找,返回所对应的标记的出现次数。
Trie树的结构非常好懂,实际上,它的节点中不仅能存储字符,还可以存储数字和一些别的东西,在下一篇文章中,Trie树则存储了二进制数字,具体内容请期待下周周六我所发的文章。
代码
下面给出Trie树之字符串统计问题的实现代码:
int son[N][26],cnt[N],idx;
void insert(char *str){
int p=0;
for(int i=0;str[i];i++){
int u=str[i]-'a';
if(!son[p][u]) son[p][u]=++idx;
p=son[p][u];
}
cnt[p]++;
}
int query(char *str){
int p=0;
for(int i=0;str[i];i++){
int u=str[i]-'a';
if(!son[p][u]) return 0;
p=son[p][u];
}
return cnt[p];
}
上一篇-KMP算法的实现 C++算法基础专栏文章 下一篇-Trie树之最大异或对问题
每周六更新一篇文章,内容一般是自己总结的经验或是在其他网站上整理的优质内容
点个赞,关注一下呗~