文章目录
字典树的介绍和使用
1. 什么是字典树
字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。—百度百科
由此我们可以总结,字典树可以用于快速查找字符串是否存在,
例如,我们有一个字符串数组
vector<string> vec = {
"ac","ad","ba","bde","c","cde","cdf"};
我们想要查询到以cd为前缀的字符串,我们需要对所有的字符串进行字符比较,当数据量大时会浪费许多时间。这类问题便可以使用字典树解决。(如下图,红色标记表示单词结束)
当查询cd前缀的字符串时,只需要统计d的非空子节点即可。
2. 字典树的实现
2.1 节点设计
目前我们了解到字典树应该是一种多叉树模型,但普通的多叉树的节点构成应该是这样的。
struct TreeNode {
//节点值
int val;
//存放孩子节点的数组
vector<TreeNode*> children;
};
字典树与其相似,但我们不再需要节点值,而是以一种标记来确定某个字符是不是当前字符串的结尾,并利用一个字母映射表来找到父节点的下一个节点。由此,我们可以写出字典树的节点设计:
struct TrieNode {
//标记当前是否是字符串末尾
bool isEnd;
//下一位可能出现的26个字母表
vector<TrieNode*> children;
//构造函数
TrieNode() {
isEnd = false;
children = vector<TrieNode*>(26, nullptr);
}
};
2.2 插入字符串
例如:我们要向Trie
中插入一个字符串"cdf",但我们之前已经插入过拥有共同前缀的单词"cde"了,我们只需要在d后申请一个新节点即可。
综上所述,我们得到一个字符串word
,应该先去比较他的前缀,如果已有共同前缀,继续向他的孩子节点搜索。当孩子节点为nullptr
,就要为其申请新节点,直到word
全部插入字典树,最后将他的尾节点标记isEnd
设置为True
。代码如下:
void insert(string word) {
//树的根节点
Trie* node = this;
//遍历字符串word
for (auto c : word) {
//因为数组存储范围是0~25 所以需要对所有字符做减'a'操作
int cur = c - 'a';
//如果当前已经走到叶子节点
if (node->children[cur] == nullptr) {
//为新字母开辟节点
node->children[cur] = new Trie();