一:概念:
又称单词查找树,Trie树,是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
利用公共前缀,减少比较,节省空间。
二:图示:
可以发现,建立过程是,对于当前字母,有路,就走过去,否则,建一个新节点。
三:在数组中的建立过程图示
引入:mp[][26],cnt[]
画的不好~~
idx,以索引来记录每个字符的位置
可以发现,每一个mp[p][字母],都是本字母的下一个字母的索引位置:
比如上图的cdf,mp[0][c]==6,接下来找mp[6][d]是否存在,存在,是7,那么找mp[7][f]是否存在,发现存在,而且cnt[8]==1,则cdf为一个单词。这就是查找的过程。
同理,建树也是一样,mp[][]不存在,就新建一个结点++idx。
四:板子代码:
以上图为例:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
char s[maxn];
int mp[maxn][29],cnt[maxn];
int idx=0;
void insert()
{
int p = 0;
for(int i=0;s[i];i++)
{
int u=s[i]-'a';
if(!mp[p][u]) //没有字母,所以新建。否则顺着走过去,跳到p=mp[p][u]
mp[p][u]=++idx;
p=mp[p][u];
}
cnt[p]++; //p处即为一个单词,++
}
int query()
{
int p = 0;
for(int i=0;s[i];i++)
{
int u = s[i] - 'a';
if(!mp[p][u]) //没路,说明没这个单词,直接结束
return 0;
p=mp[p][u];
}
return cnt[p]; //返回此单词出现次数。
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
char op[4];
scanf("%s%s",op,s);
if(op[0]=='I')
insert();
else
cout<<query()<<endl;
}
return 0;
}