Previous
树结构算法总结(1) 二叉树的遍历
树结构算法总结(2) 线段树Segment Tree
树结构算法总结(3) 字典树Trie Tree
字典树的数据结构
定义
字典树,又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
字典树是一种存储字典(中文或英文都可以)的树结构,创建/添加/查询单词的时间复杂度都为O(h),h为树高度。
应用
- 串的快速匹配:在建立的字典树里可以快速查找到想要的单词,以判定词在不在熟词表里。
- 串的排序:对Trie树进行前序遍历,就是串排序结果。
- 最长公共前缀:可以求出两个或多个字串的最大公共前缀。
数据结构
一般的字典树的节点单元包含:
- count:存储该单词在词典中出现的次数
- word:存储该节点的单词
- isword:判定该节点是否是一个有效单词
- next:存储该节点的所有孩子节点(如果只包含小写字母,则为26个)
我们直接通过lintcode上面的题目来实现简单的Trie树结构。
class TrieNode {
public:
// Initialize your data structure here.
bool isword;
int count;
// string word;
vector<TrieNode*> next;
TrieNode() {
isword = false;
next = vector<TrieNode*>(26, NULL);
// count = 0;
}
};
字典树的单词添加和查找
考虑字典树的结构特性,我们通过如下方式实现添加和查找。
class Trie {
public:
Trie() {
root = new TrieNode();
}
// Inserts a word into the trie.
void insert(string word) {
TrieNode* r = root;
for(auto i:word){
if(r->next[i-'a']==NULL)
r->next[i-'a'] = new TrieNode();
r = r->next[i-'a'];
// r->count++;
}
// r->word = word;
r->isword = true;
// r->count++;
}
// Returns if the word is in the trie.
bool search(string word) {
TrieNode* r = root;
if(r==NULL)
return false;
for(auto i:word){
if(r->next[i-'a']==NULL)
return false;
r = r->next[i-'a'];
}
if(r==NULL)
return false;
return r->isword;
}
// Returns if there is any word in the trie
// that starts with the given prefix.
bool startsWith(string prefix) {
TrieNode* r = root;
if(r==NULL)
return false;
for(auto i:prefix){
if(r->next[i-'a']==NULL)
return false;
r = r->next[i-'a'];
}
return true;
}
private:
TrieNode* root;
};
现在再增加一点新的东西,比如在查找过程中单词除了小写字母外,还包含’.’代表匹配任意一个字母,则实现方法如下(和上面的有些不太一样)。
class TrieNode{
public:
int count;
vector<TrieNode*> next;
TrieNode(){
count=0;
next=vector<TrieNode*>(26, NULL);
}
};
class WordDictionary {
public:
WordDictionary(){
root = new TrieNode();
}
// Adds a word into the data structure.
void addWord(string word) {
// Write your code here
TrieNode* r = root;
for(auto i:word){
if(!r->next[i-'a'])
r->next[i-'a'] = new TrieNode();
r = r->next[i-'a'];
}
r->count++;
}
// Returns if the word is in the data structure. A word could
// contain the dot character '.' to represent any one letter.
bool search(string word) {
// Write your code here
return searchPoint(word, root, 0);
}
bool searchPoint(string& word, TrieNode* cur, int start){
if(cur&&start==word.size())
return cur->count>0;
if(!cur)
return false;
char c = word[start];
if(c=='.'){
for(auto child:cur->next){
if(child&&searchPoint(word, child, start+1))
return true;
}
return false;
}
else{
if(cur->next[c-'a'])
return searchPoint(word, cur->next[c-'a'], start+1);
else
return false;
}
}
private:
TrieNode* root;
};
// Your WordDictionary object will be instantiated and called as such:
// WordDictionary wordDictionary;
// wordDictionary.addWord("word");
// wordDictionary.search("pattern");