一.Trie树
1.Trie 定义
> Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
>
> Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
>
> 它有3个基本性质:
>
> 1.根节点不包含字符,除根节点外每一个节点都只包含一个字符。
> 2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
> 3.每个节点的所有子节点包含的字符都不相同。
为什么查询效率比哈希表高?
首先我们来看下桶状哈希表慢在哪里,有2点:
1.对每个字符串key都要执行一次哈希散列函数
2.如果哈希散列有冲突的话,就要做冲突处理
ok,如上图所示,对于每一个节点,从根遍历到他的过程就是一个单词,如果这个节点被标记为红色,就表示这个单词存在,否则不存在。
那么,对于一个单词,我只要顺着它从根走到对应的节点,再看这个节点是否被标记为红色就可以知道它是否出现过了。把这个节点标记为红色,就相当于插入了这个单词。
这样一来我们查询和插入可以一起完成(重点体会这个查询和插入是如何一起完成的,),所用时间仅仅为单词长度。
我们可以看到,trie树每一层的节点数是26^i级别的。所以为了节省空间。我们用动态链表,或者用数组来模拟动态。空间的花费,不会超过单词数×单词长度。
二. 实现
class TrieNode
{
public:
TrieNode *next[26];
bool is_word;
// Initialize your data structure here.
TrieNode(bool b = false)
{
memset(next, 0, sizeof(next));
is_word = b;
}
};
class Trie
{
TrieNode *root;
public:
Trie()
{
root = new TrieNode();
}
// Inserts a word into the trie.
void insert(string s)
{
TrieNode *p = root;
for(int i = 0; i < s.size(); ++ i)
{
if(p -> next[s[i] - 'a'] == NULL)
p -> next[s[i] - 'a'] = new TrieNode();
p = p -> next[s[i] - 'a'];
}
p -> is_word = true;
}
// Returns if the word is in the trie.
bool search(string key)
{
TrieNode *p = find(key);
return p != NULL && p -> is_word;
}
// Returns if there is any word in the trie
// that starts with the given prefix.
bool startsWith(string prefix)
{
return find(prefix) != NULL;
}
private:
TrieNode* find(string key)
{
TrieNode *p = root;
for(int i = 0; i < key.size() && p != NULL; ++ i)
p = p -> next[key[i] - 'a'];
return p;
}
};
从Trie树(字典树)谈到后缀树(10.28修订)
http://blog.csdn.net/v_july_v/article/details/6897097