数据结构介绍
Trie:高效地存储和查找字符串集合的数据结构
先摆上y总的例子:
数据结构特点:
- 总体上看上去是一棵树
- 每个结点最少可以没有子节点,最多可以有26个子节点(对应26个字母)
- 对于表示字符串的最后一个字符的结点,在其上作特殊的标记,表示其结束
- 假设从树的根节点到树中一个有结束标记的非根节点,存在一条路径,那么把这条路径上经过的结点连起来,必然是字符串集合中的一个字符串。
- 这里表面上是用点存字符,实际上是利用的边表示字符。
模板代码
#include <iostream>
using namespace std;
const int N = 100010;
int son[N][26], cnt[N], idx;
char str[N];
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];
}
int main()
{
int n;
scanf("%d", &n);
while (n -- )
{
char op[2];
scanf("%s%s", op, str);
if (*op == 'I') insert(str);
else printf("%d\n", query(str));
}
return 0;
}
作者:yxc
链接:https://www.acwing.com/activity/content/code/content/45282/
来源:AcWing 835题
代码细节解释:(用静态数组模拟Trie树)
- son[N][26] 表示Trie树上每个结点的数据结构
son[][26]这里每一行表示树中一个结点,行的序号表示结点的编号,每行中有26列,初始值都为0,表示最多可以有26个子节点
son[m][n]的值表示m号结点的第n+1个子节点的序号
son[0][…]这一行表示根节点
每次存储时,都有一个把所有小写英文字母往0…25这26个数字映射的过程,用 - ‘a’ 来实现。 - cnt[p]存放的是判断字符串是否结束的标记,同时其数值又表示了以其下标为序号的结点作为字符串结束点的该字符串出现的个数。初始值为0,表示以序号p为结束的结点的字符串不存在,若不是0,则说明以序号p作为字符串结束的字符串有cnt[p]个
- idx:非常经典的数组空间分配符号,用来辅助静态数组模拟树时,为新的节点在数组中分配空间
每当创建新的结点时,将数组中++idx的位置分配给它。因而,数组中结点的顺序和树中的顺序是无关的。树中的结点是通过存放在son数组中的值联系起来的。