trie树,又称前缀树,是一种用来处理判断某个单词在所有单词(词典)中作为前缀的次数。 它本质上是一个DFA,效率比普通hash要高,采用了以时间换取空间的策略。详细的信息可以参考《算法-前缀树》或者hihocoder中trie树中的提示。
trie树的思想是及其简单的,稍微看上面的文章就可以读懂,下面直接给出模板:
const int MAX = 26;
//Trie树
class TrieTree{
private:
class Node{
public:
int cnt; //以到该字母为止的前缀的单词个数
bool end_flag; //到该字母为止的前缀是否是一个完整单词
Node* next[MAX]; //下一个字母
Node(){
cnt = 0;
end_flag = false;
memset(next, 0, sizeof(next));
}
};
Node* root;
public:
TrieTree(){
root = new Node();
}
//添加一个单词
void insert(const string& s){
int len = s.size(), t;
Node* p = root;
for(int i = 0 ; i < len; i++){
t = s[i] - 'a';
if(p->next[t] == NULL)
p->next[t] = new Node();
p->cnt ++;
p = p->next[t];
}
p->end_flag = true;
p->cnt++;
}
//查找以s为前缀的单词的个数
int search(const string& s){
int len = s.length();
if(len == 0)
return 0;
Node* p = root;
for(int i = 0 ; i < len; i++){
int id = s[i] - 'a';
if(p->next[id] == NULL)
return 0;
p = p->next[id];
}
return p->cnt;
}
};
注意到上面的每个节点保存的儿子是一个sons的数组,这样一来空间开销很大,如果内存不够,可以考虑“左儿子,右兄弟”的存储方法,或者采取压缩字串的方法。不过一般情况下,如果是比赛题目,空间往往足够,不用这么麻烦。</span>