数据结构可视化:https://www.cs.usfca.edu/~galles/visualization/Trie.html
字典树结构,每个结点有两个成员。
struct TrieNode {
bool isWorldEnd; // 标记当前字母是否为单词的结尾
TrieNode* children[26]; // 使用26个位置标记字母
}
其中,children数组的26个位置分别代表26个字母。children初始状态都为nullptr,如果children[i] 不为nullptr,则表示当前结点有字母(i+‘a’)。
如图所示,如果我们存储book,与bone,则字典树结构为:
如果我们还想存一个books,只需在原有book前缀的基础上在增加一个字母s即可。
代码:
class Trie {
private:
vector<Trie*> children; // 26个字母
bool isEnd; // 标记是否为单词结尾
// 查找
Trie* searchPrefix(string prefix) {
Trie* node = this;
for (char ch : prefix) {
ch -= 'a'; // 以ascii充当下标
if (node->children[ch] == nullptr) {
return nullptr; // 查找前缀不存在
}
node = node->children[ch]; // 继续向下查找
}
return node; // 找到符合要求的尾结点
}
public:
Trie() : children(26), isEnd(false) {}
void insert(string word) {
Trie* node = this;
for (char ch : word) {
ch -= 'a';
// 如果结点不存在,则新建节点保存当前字母
if (node->children[ch] == nullptr) {
node->children[ch] = new Trie();
}
node = node->children[ch];
}
node->isEnd = true; // 标志单词结尾
}
bool search(string word) {
Trie* node = this->searchPrefix(word);
return node != nullptr && node->isEnd;
}
// 是否存在某个单词的前缀
bool startsWith(string prefix) {
return this->searchPrefix(prefix) != nullptr;
}
};
练习: