首页 > 技术文章 > Trie树

txltxl22 2019-03-12 15:05 原文

今天做leetcode遇到trie树构建,学习了一下。

  Trie树,前缀树,又称字典树,核心思想是把搜索过的字符串存储起来,这样如果以后搜索得字符串的前缀存在树中,那么这部分的搜索时间就可以节省了,极大提高了信息搜索的时间效率,是空间换时间的一个典型应用。

  Trie树有这样几个特点:

1.根节点不包含字符,除根节点外,每个节点都只包含一个字符。

2.从根节点到某一个节点经过的路径连起来是一个加入的字符串。

3.每个节点的所有子节点包含的字符都不相同。

图例如下:

  如图所示,从根节点遍历到某一个节点代表一个单词,如果节点标记为红色,说明要搜索的字符串存在。有共同前缀的单词共享前缀路径,叶子节点就是单词本身。

  插入和查询操作是可以同步的,比如对于上图,要查询abe是否存在,步骤如下:

1、考察a是否存在,发现存在,则遍历到a,同理,b是a的子节点,沿这条路继续走;

2、考察ab的子节点有没有e,发现不存在,则创建ab的子节点abe,并把边ab->abe标记为e。

 前缀树的应用也有很多,比如搜索引擎、拼写检查、IP路由(最长前缀匹配)、九宫格输入法等等。

 

实现代码:(leetcode#208)

class TrieNode{
    friend class Trie;
public:
    TrieNode(){
        memset(next, 0, sizeof(next));
        is_word = false;
    }
   
private: 
    TrieNode* next[26];
    bool is_word;
};

class Trie {
public:
    /** Initialize your data structure here. */
    Trie() {
        root = new TrieNode();
    }
    
    ~Trie(){
        delete root;
    }
    
    /** Inserts a word into the trie. */
    void insert(string word) {
        TrieNode* p = root;
        int size = word.size();
        for(int i = 0; i < size; i++){
            if(p->next[word[i] - 'a'] == NULL){
                p->next[word[i] - 'a'] = new TrieNode;
                p = p->next[word[i] - 'a'];
            }
            else
                p = p->next[word[i] - 'a'];
        }
        p->is_word = true;
    }
    
    /** Returns if the word is in the trie. */
    bool search(string word) {
        return find(word) != NULL && find(word)->is_word;
        
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {
        return find(prefix) != NULL;
    }
    
    TrieNode* find(string word){
        TrieNode* p = root;
        int size = word.size();
        for(int i = 0; i < size; i++)
        {
            if(p->next[word[i] - 'a'] == NULL) return NULL;
            else p = p->next[word[i] - 'a'];
        }
        return p;
    }
    
private:
    TrieNode* root;
    
};

 

推荐阅读