Trie树(前缀树)
Posted 叶孤城_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Trie树(前缀树)相关的知识,希望对你有一定的参考价值。
前缀树简介
什么是前缀树?
前缀树是N叉树的一种特殊形式。通常来说,一个前缀树是用来存储字符串的。前缀树的每一个节点代表一个字符串(前缀)。每一个节点会有多个子节点,通往不同子节点的路径上有着不同的字符。子节点代表的字符串是由节点本身的原始字符串,以及通往该子节点路径上所有的字符组成的。
下面是前缀树的一个例子:
在上图示例中,我们在节点中标记的值是该节点对应表示的字符串。例如,我们从根节点开始,选择第二条路径 ‘b’,然后选择它的第一个子节点 ‘a’,接下来继续选择子节点 ‘d’,我们最终会到达叶节点 “bad”。节点的值是由从根节点开始,与其经过的路径中的字符按顺序形成的。
值得注意的是,根节点表示空字符串。
前缀树的一个重要的特性是,节点所有的后代都与该节点相关的字符串有着共同的前缀。这就是前缀树名称的由来。
前缀树有着广泛的应用,例如自动补全,拼写检查等等。
实现前缀树
Trie,又称前缀树或字典树,是一棵有根树,其每个节点包含以下字段
- 指向子节点的指针数组 children
- 布尔字段 is_end,表示该节点是否为字符串的结尾
插入字符串
从字典树的根开始,插入字符串。对于当前字符对应的子节点,有两种情况:
- 子节点存在。沿着指针移动到子节点,继续处理下一个字符
- 子节点不存在。创建一个新的子节点,记录在 children 数组的对应位置上,然后沿着指针移动到子节点,继续搜索下一个字符
重复以上步骤,直到处理字符串的最后一个字符,然后将当前节点标记为字符串的结尾。
查找前缀
我们从字典树的根开始,查找前缀。对于当前字符对应的子节点,有两种情况:
- 子节点存在。沿着指针移动到子节点,继续搜索下一个字符
- 子节点不存在。说明字典树中不包含该前缀,返回空指针
重复以上步骤,直到返回空指针或搜索完前缀的最后一个字符。
若搜索到了前缀的末尾,就说明字典树中存在该前缀。此外,若前缀末尾对应节点的 is_end 为真,则说明字典树中存在该字符串。
代码
这里设所有字符都是小写英文字母,共26个。
#define N 26
class Trie {
private:
struct TrieNode{
TrieNode* children[N];
bool is_end;
TrieNode(){
for(int i=0;i<N;i++) children[i]=nullptr;
is_end=false;
}
};
TrieNode* root;
public:
/** Initialize your data structure here. */
Trie() {
root=new TrieNode();
}
/** Inserts a word into the trie. */
void insert(string word) {
auto cur=root;
for(char w:word){
int idx=w-'a';
if(!cur->children[idx]){
cur->children[idx]=new TrieNode();
}
cur=cur->children[idx];
}
cur->is_end=true;
}
/** Returns if the word is in the trie. */
bool search(string word) {
auto cur=root;
for(char w:word){
int idx=w-'a';
if(!cur->children[idx]) return false;
cur=cur->children[idx];
}
return cur->is_end==true;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
auto cur=root;
for(char p:prefix){
int idx=p-'a';
if(!cur->children[idx]) return false;
cur=cur->children[idx];
}
return true;
}
};
以上是关于Trie树(前缀树)的主要内容,如果未能解决你的问题,请参考以下文章