以树形结构存储大量字符串——字典树
SuperJvRuo
2018-07-23 16:20:18
学习目标:熟练写出trie树
### 一、什么是字典树
字典树即trie树,是~~一种在工程中没有任何卵用的数据结构,~~在信息竞赛中应用广泛的数据结构。同时,它也是AC自动机的基础。
### 二、字典树的结构
如果字符串的字符集是小写英文字母,那么字典树是26叉树。字符集有多大,每个节点就有多少个子节点。
因此,以小写英文字母为字符集,字典树的节点形式如下:
```
struct Node
{
int ch[26],cnt,isEnd;
}
```
其中,```ch[26]```代表26个子节点的模拟指针,```cnt```表示经过这里的字符串个数,```isEnd```表示它是几个字符串的结尾节点。这些可以根据需要增减。
不难发现,根节点到一个```isEnd!=0```的节点的路径代表一个字符串,根节点到一个```cnt!=0```的节点的路径代表一个前缀。
![](https://cdn.luogu.com.cn/upload/pic/24838.png)
像这样。
### 三、字典树的插入
首先要有一个根节点。
```
int root=0;
```
还要给子节点分配内存。
```
int cnt=0;
```
每当要加入节点时,分配下标```++cnt```。
然后,依据字符串从前到后的每个字符在字典树上走路,直到走完,一路上维护信息:
```
using std::string;
void insert(string s)
{
int now=root;
for(int i=0;i<s.length();++i)
{
++node[now].cnt;
if(!node[now].ch[s[i]-'a'])
{
node[now].ch[s[i]-'a']=++cnt;
}
now=node[now].ch[s[i]-'a'];
}
++node[now].cnt;
++node[now].isEnd;
}
```
### 四、字典树的查询
#### 1、查询字符串
[P2580 于是他错误的点名开始了](https://www.luogu.org/problemnew/show/P2580)
像这道题。
trie树的查询和插入非常相似,只要在树上走路即可:
```
bool count(string s)
{
int now=root;
for(int i=0;i<s.length();++i)
{
if(!node[now].ch[s[i]-'a'])
return false;
}
return node[now].isEnd;
}
```
#### 2、查询前缀
把最后一行改成
```
return true;
```
即可。
### 五、例题
[P2922 USACO08DEC 秘密消息Secret Message](https://www.luogu.org/problemnew/show/P2922)
[P4683 IOI2008 Type Printer 打印机](https://www.luogu.org/problemnew/show/P4683)