Trie树(前缀树)

Posted 除了心跳都忘掉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Trie树(前缀树)相关的知识,希望对你有一定的参考价值。

前缀树简介

什么是前缀树?

前缀树是N叉树的一种特殊形式。通常来说,一个前缀树是用来存储字符串的。前缀树的每一个节点代表一个字符串(前缀)。每一个节点会有多个子节点,通往不同子节点的路径上有着不同的字符。子节点代表的字符串是由节点本身的原始字符串,以及通往该子节点路径上所有的字符组成的。

下面是前缀树的一个例子:

在上图示例中,我们在节点中标记的值是该节点对应表示的字符串。例如,我们从根节点开始,选择第二条路径 ‘b’,然后选择它的第一个子节点 ‘a’,接下来继续选择子节点 ‘d’,我们最终会到达叶节点 “bad”。节点的值是由从根节点开始,与其经过的路径中的字符按顺序形成的。

值得注意的是,根节点表示空字符串

前缀树的一个重要的特性是,节点所有的后代都与该节点相关的字符串有着共同的前缀。这就是前缀树名称的由来。

前缀树有着广泛的应用,例如自动补全,拼写检查等等。

实现前缀树

Trie,又称前缀树或字典树,是一棵有根树,其每个节点包含以下字段

  1. 指向子节点的指针数组 children
  2. 布尔字段 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树(前缀树)的主要内容,如果未能解决你的问题,请参考以下文章

数据结构——前缀树

可持久化字典树

习题:荷马史诗(哈夫曼树&贪心)

字典树208. 实现 Trie (前缀树)

前缀树(字典树/Trie) -----Java实现

208. 实现 Trie (前缀树)-字典树