前缀树
是关于“字典”的一棵树。即:它是对于字典的一种存储方式。
这个词典中的每个“单词”就是从根节点出发一直到某一个目标节点的路径,路径中每条边的字母连起来就是一个单词。
上图到橙色节点(目标节点)所组成的单词分别为:
a、abc、bac、bbc、ca
功能:
- 维护字符串集合(即字典)
- 向字符串集合中插入字符串(即建树)
- 查询字符串集合中是否有某个字符串
- 统计字符串在集合中出现的个数
- 将字符串集合按字典序排序
- 求集合内两个字符串的LCP(Longest Common Prefix 最长公共前缀)
结点结构体定义:
#define MAXSIZE 26
struct node {
bool flag; //若结点是单词的结尾,值为 true,否则为 false
int next[MAXSIZE]; //指向后继的游标数组
}trie[1000001];
插入
void Insert(string str, int &space)
{
int order;
int idx = 1; //从第一层向下挖掘
for (int i = 0; i < str.length(); i++)
{
order = str[i] - 'a'; //将字符转换为其在字母表的顺序
if (trie[idx].next[order] == 0) //若 idx 没有该字符的子结点
{
trie[idx].next[order] = space++; //启用第 space 号结点,拷贝新结点的编号
idx = trie[idx].next[order]; //idx 结点的对应字母的后继为 space
trie[idx].flag = false; //标记新结点不是单词的结尾
}
else
idx = trie[idx].next[order]; //前缀已存在,继续挖掘
}
trie[idx].flag = true; //flag 成员设置为 true,表示单词结尾
}
查找
bool Find(string str)
{
int order;
int idx = 1; //从第一层向下挖掘
for (int i = 0; i < str.length(); i++)
{
order = str[i] - 'a'; //将字符转换为其在字母表的顺序
if (trie[idx].next[order] == 0) //若字母失配,匹配结束
{
return false;
}
idx = trie[idx].next[order]; //存在对应字母,匹配继续
}
if (trie[idx].flag == false) //若成功匹配,但是不为单词结尾
return false;
else
return true; //单词匹配成功,返回 true
}