跟着y总学习了一下Trie树相关内容,当时理解的时候有些问题,将模板记录下来,感觉用数组存储节点有一些绕~:
// Trie树的总节点数
const int N = 100000;
/* son用来存储每节点的next地址 N是总节点数 26是每个节点最多的子节点数目
下一个节点所代表的字符是 第二维的index
举例子:
son[2][1] = 4 表示第二个节点的存在一个为b字符的下一个节点,为b字符的下一个节点地址是4(在son中第一维的位置);
*/
int son[N][26];
// 存储当前节点是否为结束节点
bool isEnd[N];
// 统计总的节点数目
int idx = 0;
void insert(string word){
int p = 0;
for(auto& c : word){
int u = c - 'a';
// 如果当前节点 不存在 c 字符的子节点 就创建一个
if(son[p][u] == 0) son[p][u] = ++idx;
// 相当于链表遍历中的指针下移, 只不过下一个位置的地址,存在 son[p][u]中
p = son[p][u];
}
// 将最后一个节点 标记为结束节点
isEnd[p] = true;
return;
}
void search(string word){
int p = 0;
for(auto& c : word){
int u = c - 'a';
if(son[p][u] == 0) return false;
p = son[p][u];
}
return true;
}
理解上面的内容之后,做一下leetcode的208. 实现 Trie (前缀树):
class Trie {
Trie* children[26];
bool isEnd;
public:
Trie() {
for(int i=0; i<26; i++) children[i] = NULL;
isEnd = false;
}
// 插入
void insert(string word) {
Trie* point = this;
for(auto& c : word){
int u = c - 'a';
if(point->children[u] == NULL){
// 如果下一个节点为空
Trie* node = new Trie();
point->children[u] = node;
}
point = point->children[u];
}
point->isEnd = true;
}
// 查找
bool search(string word) {
Trie* point = this;
for(auto& c : word){
int u = c - 'a';
if(point->children[u] == NULL){
// 说明该u节点不存在
return false;
}
point = point->children[u];
}
return point->isEnd;
}
bool startsWith(string prefix) {
Trie* point = this;
for(auto& c : prefix){
int u = c - 'a';
if(point->children[u] == NULL) return false;
point = point->children[u];
}
return true;
}
};