思路:
- 前缀树又称字典树,用来快速查询新的字符串是否在当前的字典中,如果没有,就将其插入到字典中。用途就是模糊搜索(比如代码补全),本质上是一棵26叉树。
- 对于树中的每一个节点,其数据结构都是一个
bool数据 + 26个分叉指针。如果父亲节点的子节点不为空,说明该子节点索引对应的字符存在字典中。
bool is_end;Trie* next[26];

为了便于逻辑上的理解,主流的画法是不画出空节点。
- 分成两个操作:插入、查询
- 插入操作,一直往下搜索,如果遇到
nullptr,就逐个把剩下的字符插入到字典树当中
void insert(string word) {Trie* node = this;for (char ch: word) {if (node->next[ch - 'a'] == nullptr) {// 父亲节点有子节点了,就说明当前位置存储了子节点索引所对应的字符node->next[ch - 'a'] = new Trie();}node = node->next[ch - 'a'];}node->is_end = true;}
- 查询操作更加直观,顺着数组中的每一个字母不断往下搜索,如果遇到了
nullptr,那么就说明数组中的所有字符并没有完全存在字典树当中,返回false,如果读完了整个数组,那么还要判断当前位置的is_end,说不定现在的数组,只是之前的字典树中存储的记录的一部分呢。
bool search(string word) {Trie* node = this;for (char ch: word) {node = node->next[ch - 'a'];if (node == nullptr) {return false;}}return node->is_end;}
- 搜索前缀更加简单,和普通搜索差不多,最后改成返回
true即可。
bool startsWith(string prefix) {Trie* node = this;for (char ch: prefix) {node = node->next[ch - 'a'];if (node == nullptr) {return false;}}return true;}
代码:
class Trie {private:bool is_end;Trie* next[26];public:Trie() {is_end = false;memset(next, 0, sizeof(next));}void insert(string word) {Trie* node = this;for (char ch: word) {if (node->next[ch - 'a'] == nullptr) {// 父亲节点有子节点了,就说明当前位置存储了子节点索引所对应的字符node->next[ch - 'a'] = new Trie();}node = node->next[ch - 'a'];}node->is_end = true;}bool search(string word) {Trie* node = this;for (char ch: word) {node = node->next[ch - 'a'];if (node == nullptr) {return false;}}return node->is_end;}bool startsWith(string prefix) {Trie* node = this;for (char ch: prefix) {node = node->next[ch - 'a'];if (node == nullptr) {return false;}}return true;}};/*** 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);*/
