【C++】字典树Trietree

字典树

今天刷题实现一个魔法字典(https://leetcode.cn/problems/implement-magic-dictionary/),用了map暴力求解以后AC了,看题解时发现了字典树,感觉设计还是很精妙的,在搜索效率上有提升。故总结一下字典树来学习学习。

字典树也是一种使用空间换时间的数据结构,也叫做前缀树(一下子就熟悉了),可以用于统计、排序和保存大量字符串而不用重复存储字符串的公共部分。
主要思想就是利用字符串的公共前缀作为父结点来节约存储空间。

【C++】字典树Trietree_第1张图片

设计字典树

当字符是26个小写字符,就可以把26个字符预留当作是当前节点可能的子节点,也就是当前字符串作为前缀的下一个字符。

  • Trie() 初始化前缀树对象。
  • void insert(string word) 向前缀树中插入字符串word。
  • bool search(string word) 如果字符串word在前缀树中,返回true;否则,返回false。
  • bool startsWith(string prefix) 如果之前已经插入的字符串word的前缀之一为prefix ,返回true;否则,返回false。

对于一个字典树Trie类,肯定是要有一个根节点root的,放一个26个大小的TrieNode类型数组,分别对应’a’-'z’的字符,同时用一个bool类型变量isEnd表示是否为字符串末尾结束。

class Trie {
private:
    vector<Trie*> children;
    bool isEnd;

    Trie* searchPrefix(string prefix) {
        Trie* node = this;
        for (char ch : prefix) {
            ch -= 'a';
            if (node->children[ch] == nullptr) {
                return nullptr;
            }
            node = node->children[ch];
        }
        return node;
    }

public:
    Trie() : children(26), isEnd(false) {}

    void insert(string word) {
        Trie* node = this;
        for (char ch : word) {
            ch -= 'a';
            if (node->children[ch] == nullptr) {
                node->children[ch] = new Trie();
            }
            node = node->children[ch];
        }
        node->isEnd = true;
    }

    bool search(string word) {
        Trie* node = this->searchPrefix(word);
        return node != nullptr && node->isEnd;
    }

    bool startsWith(string prefix) {
        return this->searchPrefix(prefix) != nullptr;
    }
};

插入操作:遍历字符串,同时从字典树root节点开始遍历,找到每个字符对应的位置首先判断是否为空,如果为空需要创建一个新的Trie。不过重要的是要在停止的那个TrieNode将isEnd设为true表明这个节点是构成字符串的末尾节点。

查询操作: 查询是建立在字典树已经建好的情况下,这个过程和查询有些类似但不需要创建TrieNode,如果枚举的过程一旦发现该TrieNode未被初始化(即为空)则返回false,如果顺利到最后看看该节点的isEnd是否为true(是否已插入已改字符结尾的字符串),如果为true则返回true。

前缀查找:和查询很相似但是有点区别,查找失败的话返回false,但是如果能进行到最后一步那么返回true。

你可能感兴趣的:(C++,c++,算法,开发语言)