1 字典树
Trie树又称字典树,字典树的数据结构如下所示;
下面这颗字典树包含的字符串集合是{ab,aza};
每一个类Trie中包含一个vector<Trie*>children(26),和isEnd(标记一个字符串的尾);
比如我们要插入abc,先看根节点node中的的children[a-‘a’]是否有指向下一个Trie的指针,有的话代表存在第一个字符为‘a’的前缀,那么往下走,node=node->children[a-'a‘];
再看这个节点的children[b-‘a’]中有指向下一个Trie的指针,往下走,node=node->children[b-'a’];
再看这个节点的children[c-‘a’]中,没有指向下一个Trie的指针,那么就在children[c-‘a’]中存放一个Trie*指针,代表指向的Trie,继续往下走到刚刚新建的Trie,node=node->children[c-'a’];一个abc的前缀到此创建完成,node->isEnd置为true,代表这里是前缀的终点。
class Trie {
vector<Trie*>children;
bool isEnd;
Trie* searchWord(const string& word){
Trie* node=this;
for(const char& w:word){
int ch=w-'a';
if(node->children[ch]==nullptr)
return nullptr;
node=node->children[ch];
}
return node;
}
public:
/** Initialize your data structure here. */
Trie():children(26),isEnd(false) { }
/** Inserts a word into the trie. */
void insert(string word) {
Trie*node=this;
for(const char& w:word){
int ch=w-'a';
if(node->children[ch]==nullptr)
node->children[ch]=new Trie();
node=node->children[ch];
}
node->isEnd=true;
}
/** Returns if the word is in the trie. */
bool search(string word) {
Trie* node=searchWord(word);
return node!=nullptr&&node->isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Trie*node=searchWord(prefix);
return node!=nullptr;
}
};
/**
* Your Trie object will be instantiated and called as such:
* Trie* obj = new Trie();
* obj->insert(word);
* bool param_2 = obj->search(word);
* bool param_3 = obj->startsWith(prefix);
*/
2 哈希表
对比不使用字典树,用哈希表集合set的做法
每一次查看是否有以prefix为前缀的字符串,都要在遍历集合中所有字符串,并进行一一比对,直到找到前缀为prefix的字符串,效率不如字典树。
class Trie {
unordered_set<string>st;
public:
/** Initialize your data structure here. */
Trie() {
}
/** Inserts a word into the trie. */
void insert(string word) {
st.insert(word);
}
/** Returns if the word is in the trie. */
bool search(string word) {
if(st.count(word))
return true;
return false;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
int n=prefix.size();
for(auto word:st){
if(word.size()<n) continue;
int i;
for(i=0;i<n;++i){
if(word[i]!=prefix[i])
break;
}
if(i==n) return true;
}
return false;
}
};
/**
* Your Trie object will be instantiated and called as such:
* Trie* obj = new Trie();
* obj->insert(word);
* bool param_2 = obj->search(word);
* bool param_3 = obj->startsWith(prefix);
*/
3 字典树较哈希表的优势
1 字典树的查询效率是O(logL),L是字符串的长度,效率高;
2字典树支持动态查询,当我们要查询apple时,hash必须等用户把单词apple输入完毕才能hash查询。而字典是则可以。
但是字典树比较耗费空间资源。