字典树. 又称单词查找树, Trie树 ,是一种 树形结构 ,是一种哈希树的变种。经常被搜索引擎系统用于文本词频统计。. 它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
字典树与其名字一样,用其查找就像查字典一样,如果我们查找一个字符串“abcd”,那它的运行模式大概可以这样理解:从根节点出发,如果根节点有为‘a’的子结点,则去其事先储存好的索引,并以‘a’作为根节点向下搜索,如果中途没有对应的子结点则自动停止,如果有则返回结果。字典树的插入也和查找基本相同,只不过是当面对没有对应的子结点时会创建一个符合要求的子结点。
引入一个题目:
835. Trie字符串统计 - AcWing题库
代码:
#include<iostream>
#include<cstring>
using namespace std;
#define maxsize 100010
int num[maxsize][26],cnt[maxsize],len=0; /*子结点记录,第0行代表根节点,根节点不存信息*/ /*记录以某字母出现次数*/ /*cnt长度*/
void insert(string s){
int p=0;
for(int i=0;i<s.length();i++){
int x=s[i]-97;
if(num[p][x]==0)num[p][x]=++len;/*添加此结点,并注明该结点位置*/
p=num[p][x];/*将此结点作为根节点向下搜索*/
}
cnt[p]++;
}
void find(string s){
int p=0;
for(int i=0;i<s.length();i++){
int x=s[i]-97;
if(num[p][x]==0){
cout<<"0"<<endl;return;
}
p=num[p][x];/*将此结点作为根节点向下搜索*/
}
cout<<cnt[p]<<endl;
}
int main(){
memset(num,0,sizeof(num));
memset(cnt,0,sizeof(cnt));
int n;
cin>>n;
while(n--){
char c;string s;
cin>>c>>s;
if(c=='I'){
insert(s);
}
else{
find(s);
}
}
system("pause");
return 0;
}
代码较难理解的部分在于cnt数组的原理:
cnt数组储存的是以某字母结尾的字符串的出现次数,而这个字母我们事实上不需要知道它到底是谁,我们只需要它是第几个出现的,举个例子,如果我们要插入abd和abba两个字符串,那么cnt数组每个下标理论上对应的字母应该为:
loc: 1 2 3 4 5
a
a b
a b d
a b d b
a b d b a
我们会发现前后会出现相同的字母,因此字母是谁对结果并无影响。此时cnt数组为:
loc: 1 2 3 4 5
cnt: 0 0 1 0 1
因此,num数组的作用是用来搜索cnt中第i个出现字母的子结点是谁即子结点是第几个出现的字母,正如上面的例子,a结点有一个子结点是b,而b有两个子结点分别是b和d,d没有子结点,第二个b又有子结点a。