Trie树
Trie树又称字典树,是一种简单的树形数据结构,他的主要作用是高效地存储和查找字符串,其实现原理是利用字符串的公共前缀来减少查询时间,最大限度的减少无谓字符的比较,效率高。
三个基本性质
根节点不包含字符,除根节点外每一个节点都只包含一个字符;
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
每个节点的所有子节点包含的字符都不相同。
存储规则
从根节点开始,存一个字符串,先看根节点连接的子结点有没有第一个字母,有的话接着从他往下找第二个字母,以此类推;若没有某一字母,就新建一个该字母节点,连进去,再依次往下新建。对于每个结尾字符要加一个标记,标记该字母是一个字符串的结尾,我们一般用计数做标记,每以他结尾一次计数就加一,这样不仅能实现标记,0是非结尾,非0是结尾;还能统计数量。存储图如下:
若要存储左边的字符串,则建的trie树如右图所示
代码实现
int son[MAXN][26],cnt[N],idx; //son就是存的trie树,只有26个字母,因此子结点最多只有26个,cnt是统计该结点作为结尾的次数,idx是每个节点的唯一编号
void insert(string str) //插入函数
{
int p = 0; //根结点为0号,从根开始
for(int i = 0;str[i];i++) //循环字符串的每个字母
{
int u = str[i] - 'a'; //将字母转化为编号从0-25
if(!son[p][u]) //如果没有u节点
son[p][u] = ++idx; //新建一个p的子结点为u,编号为idx
p = son[p][u]; //当前结点往下走,如此循环
}
cnt[p]++; //最终的结尾节点计数++
}
int query(string str) //查询函数
{
int p = 0; //从根节点开始
for(int i = 0;str[i];i++) //循环查找的字符串的每一个字母
{
int u = str[i] - 'a'; //将字母转化为编号
if(!son[p][u]) //如果没有该结点
return 0; //返回0
p = son[p][u];
}
return cnt[p]; //返回结尾节点的个数
}
模板题
代码模板
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int N = 100010;
int son[N][26],cnt[N],n,idx;
string op,str;
void insert(string s)
{
int p = 0;
for (int i = 0;s[i]; i ++ )
{
int u = s[i] - 'a';
if(!son[p][u])
son[p][u] = ++idx;
p = son[p][u];
}
cnt[p]++;
}
int query(string s)
{
int p = 0;
for(int i = 0;s[i];i++)
{
int u = s[i] - 'a';
if(!son[p][u])
return 0;
p = son[p][u];
}
return cnt[p];
}
int main()
{
cin >> n;
for(int i = 0;i < n;i++)
{
cin >> op >> str;
if(op == "I")
insert(str);
else
cout << query(str) << endl;
}
return 0;
}