Trie树
作用:高效地存储和查找字符串集合的数据结构
用到Trie树的题字母类型不会很多,一定都会有限制
如想在Trie中存储如下元素:
abcdef
,abdef
,aced
,bcd
,bcff
,cdaa
,bcdc
,abc
存储方式如下:
在根节点root后,从头向后遍历,在每个单词的结尾位置做标记,如下图:

那么如何进行高效查找呢?
如现在想去查找aced
这个单词,如上图,会从root开始走,先走a,再走c,再走e,再走d,发现d上有红色结束标记,说明存在aced
。
如现在如查找abk
,会先从root走到a,再走b,发现不存在c,那么abc
就不存在。
1.1 练手题目

1.2 练手答案
#include<iostream>
using namespace std;
const int N = 100010;
int son[N][26]; // 因为题目说26个英文小写字母,所以子节点最多只有26
int cnt[N]; // 存储以当前这个点结尾的有多少个
int idx; // 当前用到了哪个下标,下标是0的点既是根节点又是空节点
char str[N];
void insert(char str[])
{
int p = 0;
// C++中字符串结尾是'\0'所以可以str[i]判断
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a'; // 把字母映射成0-25
// 使用idx是为了区分方便,因为可能同时并列存在多个字符'a'
// idx是全局变量一直没重置
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]; // 返回以p结尾的单词数量
}
int main()
{
int n;
cin >> n;
while(n--)
{
char op[2];
cin >> op >> str;
if(op[0] == 'I') insert(str);
else cout << query(str),puts("");
}
cout << "idx=" << idx;
return 0;
}