用unordered_map保存一个节点的所有孩子,其中字符为key和对应节点指针为value,节点还需要一个属性值is_end表明是否是一个单词的结尾
class TrieNode
{
public:
TrieNode(bool end= false) {is_end=end;}
~TrieNode()
{
for(auto elem:branches)
delete(elem.second);
}
TrieNode* find_node(char ch) //在该节点的孩子节点中找ch字符的节点
{
if(branches.find(ch)==branches.end())
return nullptr;
else
return branches[ch];
}
bool is_end; //用于标识节点是否是一个单词的结尾
unordered_map<char,TrieNode*> branches; //用来保存孩子节点以及对应的字符,因为后续需要判断孩子节点中是否有某个字符的节点,因此用map查询会高效一点。也可以用vector,其中下标为字符,值为节点指针
};
class Trie {
public:
/** Initialize your data structure here. */
Trie() {root = new TrieNode();}
~Trie() {delete(root);} //在TrieNode里会递归删除所有节点
/** Inserts a word into the trie. */
void insert(string word) {
TrieNode* cur = root;
int i=0;
for(;i<word.size();++i) //找第一个不在前缀树里的字母
{
TrieNode* tmp = cur->find_node(word[i]);
if(tmp== nullptr) break;//没找到,跳出循环
else
{
cur = tmp;
if(i==word.size()-1) //考虑要插入的已经存在,但只是某个词的前缀,因此需要更改其is_end属性
cur->is_end = true;
}
}
for(;i<word.size();++i) //将单词的剩余部分添加到树里
{
cur->branches[word[i]] = new TrieNode(i==word.size()-1? true: false); //如果是单词结束,则其is_end属性要为true
cur = cur->branches[word[i]]; //指向刚插入的节点
}
}
/** Returns if the word is in the trie. */
bool search(string word) {
TrieNode* cur = root;
for(int i=0;i<word.size();++i)
{
TrieNode* tmp=cur->find_node(word[i]);
if(tmp!= nullptr) //如果该字符存在
cur=tmp;
else
return false;
}
if(cur->is_end)
return true;
else //如果只是前缀,则返回false
return false;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
TrieNode* cur = root;
for(int i=0;i<prefix.size();++i)
{
TrieNode* tmp=cur->find_node(prefix[i]);
if(tmp!= nullptr) //如果该字符存在
cur=tmp;
else
return false;
}
return true;
}
private:
TrieNode* root; //根节点
};