前缀树 / 字典树是最简单的树了
欠的总是要还的
O(n)算法的多叉树
比较好理解没啥解释的了
用数组模拟 行结点 列指针 cnt记录最大结点编号
直接上代码吧
1.统计单词数 -> 建树
int trie[MAXN][26] = {0}, cnt = 1, ans = 0; //trie树 行结点 列指针
bool wend[MAXN] = {false}; //保存以i节点为结尾的单词是否存在
void insert(char word[])
{
int len = strlen(word), to = 1;
for(int i = 0; i < len; i++)
{
int chn = word[i] - 'a';
if(!trie[to][chn])
trie[to][chn] = ++cnt;
to = trie[to][chn];
}
if(!wend[to]) //计和
++ans;
wend[to] = true;
}
2.单词查询 -> 查询是否能在树中完全匹配
bool wend[MAXN] = {false}; //保存以i节点为结尾的单词是否存在
bool intree(char word[])
{
int len = strlen(word), to = 1;
for(int i = 0; i < len; i++)
{
int chn = word[i] - 'a';
if(! trie[to][chn])
return false;
to = trie[to][chn];
}
return wend[to]; //查询以i节点为结尾的单词是否存在
}
3.存在前缀 -> 查询是否能在树中前缀匹配
例题: http://codevs.cn/problem/4189/
bool intree(char word[]) //只要能扫到单词结尾则必定存在前缀
{
int len = strlen(word), to = 1;
for(int i = 0; i < len; i++)
{
int chn = word[i] - 'a';
if(! trie[to][chn])
return false;
to = trie[to][chn];
}
return true;
}
4.前缀统计1 -> 此单词为字典中多少单词的前缀的和
例题: http://acm.hdu.edu.cn/showproblem.php?pid=1251
int trie[MAXN][26] = {0}, sum[MAXN] = {0}, cnt = 1; //sum数组保存到此结点的前缀总和
bool wend[MAXN] = {false};
void insert(char word[])
{
int len = strlen(word), to = 1;
for(int i = 0; i < len; i++)
{
int chn = word[i] - 'a';
if(!trie[to][chn])
trie[to][chn] = ++cnt;
to = trie[to][chn];
++sum[to]; //计和
}
wend[to] = true;
}
int precnt(char word[])
{
int len = strlen(word), to = 1;
for(int i = 0; i < len; i++)
{
int chn = word[i] - 'a';
if(!trie[to][chn])
return 0; //前缀都扫不完查无此单词 和就不用想了
to = trie[to][chn];
}
return sum[to];
}
5.前缀统计2 -> 统计树中有多少单词为当前单词的前缀
例题:http://acm.ncst.edu.cn/problem.php?pid=1421
const int MAXN = 1e6 + 10;
int trie[MAXN][26] = {0}, cnt = 1;
int wend[MAXN] = {0}; //wend本用来标记单词结尾, 现在用来标记以该结点结尾的单词的数量
void insert(char word[])
{
int len = strlen(word), to = 1;
for(int i = 0; i < len; i++)
{
int chn = word[i] - 'a';
if(!trie[to][chn])
trie[to][chn] = ++cnt;
to = trie[to][chn];
}
++wend[to];
}
int precnt(char word[])
{
int len = strlen(word), to = 1, ret = 0;
for(int i = 0; i < len; i++)
{
int chn = word[i] - 'a';
if(!trie[to][chn])
break;
to = trie[to][chn];
ret += wend[to]; //路过的所有结点均为word的前缀 所以加和计算
}
return ret;
}