前缀树概念
前缀树实际上就是一种N叉树,也被称为字典树。从名字可以看出,字典树就是用来做类似于字典查找的一种数据结构,在搜索引擎中,可以用来做字符匹配,以及字符前缀相关的操作。
典型的前缀树结构如下所示:
数据结构定义如下所示:
1 | class TreeNode { |
我们用children中的每个指针的索引来表示各个字符,如果限定为小写字母,则TreeNode[26], 如果限定为ASCII字符,则为TreeNode[128]。
有了前缀树的概念,我们看下前缀树可以有哪些操作。
前缀树的操作
1 | // 下面的代码有些细节是不好的,比如public成员,以及在构造函数中new。这里我们先忽略这些问题 |
前缀树操作的代码实现
这个函数用来获取指定key的末端的位置,如果不存在key,则返回nullptr1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 获取匹配的key的位置
TreeNode* Trie::getNode(TreeNode* root, string key) {
TreeNode* p = root;
for (int i = 0; i < key.length(); ++i) {
if (p == nullptr) {
return nullptr;
}
char c = key[i];
p = p->children[c - 'a']; // 这里我们假定只是小写字母
}
return p;
}
// 获取key对应的节点值
int Trie::get(string key) {
TreeNode* node = getNode(root, key);
if (node == nullptr || node->val == -1) {
return -1;
}
return node->val;
}
1 | // 判断前缀树中是否包含节点key |
1 | // 判断是否存在前缀为prefix的健 |
1 | // 在前缀树中搜索query的最短前缀 |
1 | // 在前缀树中搜索query的最长前缀 |
1 | // 在前缀树中搜索前缀为query的所有key |
1 | // 判断是否存在前缀为prefix的key |
1 | // 查找所有符合通配符.的key |
1 | // 判断是否存在符合通配符.的key |
1 | void Trie::put(string key, int val) { |
1 | TreeNode* Trie::put(TreeNode* node, string key, int val, int i) { |
1 | // 删除key |
leetcode例题
这个题目很简单,只是要求实现insert/search/startsWith三个函数,比较简单。甚至不需要用到上面的一整套逻辑
1 | struct Node { |
这个题目跟上面的内容很相似,只是多了一个通配符’.’的处理。但是leetcode这道题的官方的超时时间设置的真的是很无语。
1 | struct Node { |
这个题目就稍微有一些复杂了,但是也不是很难,只是需要预先构造前缀树,然后分割字符串,然后从前缀树中拿到最短的前缀,然后再输出即可。
1 | class TrieNode { |
这个题目本质上就是构造前缀树,只不过需要再search的时候,添加一点点小变形而已。
1 | class TrieNode { |