Trie (发音为 "try") 或前缀树是一种树数据结构,用于检索字符串数据集中的键。这一高效的数据结构有多种应用:1. 自动补全 2.拼写检查 3.九宫格打字预测 4.IP路由(最长前缀匹配)
为什么需要Trie树结构?
哈希表可以在 O(1)O(1) 时间内寻找键值,却无法高效的完成以下操作:
- 找到具有同一前缀的全部键值。
- 按词典序枚举字符串的数据集。
Trie 树优于哈希表的另一个理由是,随着哈希表大小增加,会出现大量的冲突,时间复杂度可能增加到 O(n),其中 n是插入的键的数量。与哈希表相比,Trie 树在存储多个具有相同前缀的键时可以使用较少的空间。此时 Trie 树只需要 O(m)的时间复杂度,其中 m 为键长。而在平衡树中查找键值需要 O(mlogn) 时间复杂度。
Trie 树的结点结构
Trie 树是一个有根的树,其结点具有以下字段:
- 最多 R 个指向子结点的链接,其中每个链接对应字母表数据集中的一个字母。本文中假定 R 为 26,小写拉丁字母的数量。
- 布尔字段,以指定节点是对应键的结尾还是只是键前缀。
结构体如下:
struct TrieNode {
bool isEnd; //该结点是否是一个串的结束
TrieNode* next[26]; //字母映射表
};
初始化
Trie() {
for(int i=0;i<26;i++){
root->nodes[i] = NULL;
}
root->isEnd = true;
}
插入
void insert(string word) {
TrieNode * now = root;
for(char c : word){
if(now->nodes[c-'a'] == NULL){
now->nodes[c-'a'] = new TrieNode();
}
now= now->nodes[c-'a'];
}
now->isEnd = true;
}
查找
bool search(string word) {
TrieNode * now = root;
for(char c : word){
if(now->nodes[c-'a'] == NULL){
return false;
}
now = now->nodes[c-'a'];
}
if(now->isEnd) return true;
else return false;
}
判断前缀
bool startsWith(string prefix) {
TrieNode * now = root;
for(char c:prefix){
if(now->nodes[c-'a'] == NULL)
return false;
now = now->nodes[c-'a'];
}
return true;
}
参考自leetcode208题 实现Trie树 题目链接 https://leetcode-cn.com/problems/implement-trie-prefix-tree/
前缀树的应用:对字典实现单词搜索 https://leetcode-cn.com/problems/word-search-ii/