前缀树,或者叫字典树,是一种典型的空间换时间的字符串搜索策略。它通过将字符串逐字符的存放进一棵树的结构中,从而将一个字符串的搜索时间降至线性。LeetCode208就是关于字典树的实现,题面如下:
一个简单的键树示意图如下。红色字母表示单词的结尾,那么这棵树中存储的单词有:ab,abc,ade
对于某一个结点,不仅要存储它是否是某一个单词的结尾,还要存储指向其下一个字符的指针。类Trie包含的私有数据如下:
/*using dynamic memory allocation*/
bool End; /*indicating whether it's end*/
// Trie* Children[27]; /*array is ok, but wasting too much*/
map<char, Trie*> Children;
因为题目说,字符串中只含有小写字母,所以很多地方使用了静态数组来存储指向下一个孩子的指针,但是在实际场合下这是不可能的,它可能是任何字符集,故这里使用map来管理字符和对应指针之间的映射关系。
题目要求的实现有三个,插入新的字符串、搜索某字符串是否在树中、是否存在以某字符串为前缀的串。这三个操作均不难,所以计划后面还要探索一下删除操作的实现方法。
首先是插入操作:
/** Inserts a word into the trie. */
void insert(string word) {
/*get the pointer of present Trie*/
Trie* Present = this;
for(int i = 0 ; i < word.size() ; ++i)
/*has not been allocated*/
if(Present->Children.find(word[i]) == Present->Children.end())
{
Present->Children[word[i]] = new Trie();
Present = Present->Children[word[i]];
}
else
Present = Present->Children[word[i]];
/*set the final node's End flag as true*/
Present->End = true;
}
值得注意的是要将结尾处的结点标记为结束,即Present->End = true;
随后是搜索操作,即判断给定字符串是否在树中,思路就是从根结点出发,沿着孩子指针指向的方向一步步搜索下去,到达字串的终点之前如果就结束,就可以直接判断不在树中。如果可以一直搜索到字符串结束,这时候还要判断当前结点是否是结束的结点,而不能直接返回true;
/** Returns if the word is in the trie. */
bool search(string word) {
Trie* Present = this;
for(int i = 0 ; i < word.size() ; ++i)
if(Present->Children.find(word[i]) == Present->Children.end())
return false;
else
Present = Present->Children[word[i]];
return Present->End; /*check if it's the end*/
//return true; /*implementation of startswith*/
}
事实上,上述代码中最后直接返回true那就是探索是否有前缀的算法实现,在此不再给出代码。
删除的代码还需要思考,到时候补充上来。