Trie树

2017-10-21  本文已影响0人  wayyyy

Trie树,即字典树,又称单词查找树。经常应用于字符串的统计与排序,经常被搜索引擎系统用于文本词频统计。

核心思想是:空间换时间,利用字符串的公共前缀,来降低查询时间的开销以达到提高效率的目的

一般有以下3个性质:

Trie树.png
/* 结点 */
const int ALPHABET = 26;   //26个小写字母
struct TrieNode{
    size_t n;
    TrieNode* childrens[ALPHABET];  // 指针数组

    TrieNode(size_t n_ = 0): n(n_) {
        for (int i = 0; i != ALPHABET; i++)
            childrens[i] = nullptr;
    }
};

/* Trie树 */
class Trie
{
    ......
    private:
        TrieNode* root;    // 根节点
        size_t count;      // 记录单词的数量 
};
查找

在单词查找树中,查找分为3类情况:

Trie查找.png
size_t Trie::find(const std::string &word) const {
    if (root == nullptr)
        return 0;
    
    TrieNodePtr cur = root;
    for (const auto& ch : word) {
        if ((cur->childrens)[ch-'a'] == nullptr)
            return 0;
        cur = (cur->childrens)[ch-'a'];
    }

    return cur->n;
}
插入

在插入之前要沿着进行一次查找,此时有可能出现2种情况:

Trie插入.png
void Trie::insert(const std::string &word) {
    if (word.empty())
        return;

    if (root == nullptr)
        root = new TrieNode();

    TrieNodePtr cur = root;
    for (const auto& ch : word) {
        if ((cur->childrens)[ch-'a'] == nullptr)
            (cur->childrens)[ch - 'a'] = new TrieNode();
        cur = (cur->childrens)[ch-'a'];
    }

    count++;
    cur->n++;
}
删除

从一棵单词查找树中删去一个键,第一步是找到该键对应的节点。

Trie删除.png
void Trie::remove(const std::string &word) {
    if (word.empty())
        return;
    root = remove(root, word, 0);
}

typename Trie::TrieNodePtr Trie::remove(TrieNodePtr x, const std::string& word, size_t len){
    if (x == nullptr)
        return nullptr;
    if (len == word.size()){
        if (x->n > 0) {
            x->n = 0;
            count--;
        }
    } else
        (x->childrens)[word[len]-'a'] = remove((x->childrens)[word[len]-'a'], word, len+1);

    if (x->n > 0)
        return x;

    for(int i = 0; i != ALPHABET; i++)
        if ((x->childrens)[i] != nullptr)
            return x;

    delete x;
    return nullptr;
}
遍历
Trie遍历.png
void Trie::collect(TrieNodePtr cur, std::string& tmp, std::vector<std::string> &result){
    if (cur->n > 0)
        result.push_back(tmp);

    for (int i = 0; i != ALPHABET; i++) {
        if ((cur->childrens)[i] != nullptr) {
            tmp.append(1, static_cast<char>('a' + i));
            collect(cur->childrens[i], tmp, result);
            tmp.erase(tmp.end()-1);
        }
    }
}

性能分析

应用

上一篇 下一篇

猜你喜欢

热点阅读