Trie树

Trie树又称为前缀树(Prefix Tree)、单词查找树或键树,是一种多叉树结构。
Trie树例子
上图是一棵 Trie 树,表示了关键字集合{“a”, “to”, “tea”, “ted”, “ten”, “i”, “in”, “inn”} 。从上图可以归纳出Trie树的基本性质:

  1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
  2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
  3. 每个节点的所有子节点包含的字符都不相同。

代码实现

Trie树结点的定义:

struct TrieNode 
{
    char c;    //字符
    map<char, TrieNode *> children;    //用map维护字符到孩子结点的映射关系
    bool isWord;    //判断是否是字符串
    TrieNode(char ic =  0) : c(ic),  isWord(false) {}
};

Trie树的定义:

class Trie
{
public:
    Trie() { root = new TrieNode(); }
    void insert(const std::string &word);    //插入字符串
    bool search(const std::string &queryWord);    //查询字符串是否在Trie树中
private:
    TrieNode *root;    //根节点
};

插入字符串的实现:

void insert(const std::string &word)
{
    if(word.length() == 0) return;    //不处理word为空的情况
    TrieNode *node = root;    //从根节点开始
    for(char ch : word)
    {
        auto& children = node->children;
        //不存在目前字符的子节点
        if(children.count(ch) == 0)
        {
            node = new TrieNode(ch);    //node指向子节点
            children.insert(make_pair(ch, node);
        }
        else
            node = children[ch];    //node指向子节点
    }
    node.isWord = true;    
}

查找字符串的实现:

bool search(const std::string &queryWord)
{
    if(queryWord.length() == 0) return false;    //查询字符串为空,返回false
    TrieNode *node = root;     //从根节点开始
    for(char ch : queryWord)
    {
        auto& children = node->children;
        if(children.count(ch) == 0)    
            return false;    //不存在路径,返回false
        node = children[ch];
    }
    return node.isWord;    
}

例子

LeetCode 720. Longest Word in Dictionary(https://leetcode.com/problems/longest-word-in-dictionary/description/)
Given a list of strings words representing an English Dictionary, find the longest word in words that can be built one character at a time by other words in words. If there is more than one possible answer, return the longest word with the smallest lexicographical order.

If there is no answer, return the empty string.
问题描述:找出数组里最长的字符串,该字符串的子集也要在这个数组里,有多个答案则输出字典序最小的。
这道题可以用Trie树+BFS来处理。

class Solution {
public:
    string longestWord(vector<string>& words)
    {
        if(words.size() == 0) return string();
        
        Trie trie;
        for(string &word : words)
            trie.insert(word);
        
        return trie.longestWord();   
    }
    
    struct TrieNode
    {
        char c;
        map<char, TrieNode *> children;
        string word;
        bool isWord;
        TrieNode(char ic = 0) : c(ic), isWord(false) {}
    };
    
    class Trie
    {
    public:
        Trie()  { root = new TrieNode(); }
        
        void insert(const string &word)
        {
            if(word.length() == 0) return;
            TrieNode *node = root;
            for(char ch : word)
            {
                auto& children = node->children;
                if(children.count(ch) == 0)
                {
                    node = new TrieNode(ch);
                    children.insert(make_pair(ch, node));
                }
                else
                    node = children[ch];
            }

            node->isWord = true;
            node->word = word;           
        }
        
        string longestWord()
        {
            queue<TrieNode *> qtn;
            qtn.push(root);
            string res;            
            while(qtn.size() > 0)
            {
                TrieNode *node = qtn.front();
                qtn.pop();    
                auto& children = node->children;
                //这里使用反向迭代器来处理字典序最小
                for(auto it = children.rbegin(); it != children.rend(); ++it)  
                {
                    if((it->second->isWord))
                    {
                        res = it->second->word;
                        qtn.push(it->second);
                    }
                }
            }
            return res;           
        }    
    private:
        TrieNode *root;   
    };  
};

参考资料

  1. 百度百科 https://baike.baidu.com/item/字典树/9825209?fr=aladdin&fromid=517527&fromtitle=Trie树
  2. 字典树Trie http://blog.csdn.net/hihozoo/article/details/51248823
  3. Java Solution with Trie + BFS https://leetcode.com/problems/longest-word-in-dictionary/discuss/109113
posted @ 2018-01-30 15:52  dreamnwx1  阅读(146)  评论(0编辑  收藏  举报