Trie树是一种树数据结构,用于检索字符串数据集中的键。
主要应用有:
1.自动补全
2.拼写检查
3.IP路由(最长前缀匹配)
4.T9打字预测
5.单词游戏
比哈希表的优势在于
一、可高效的完成
1.找到具有同一前缀的全部键值
2.按词典序枚举字符串的数据集
二、
随着哈希表大小增加,冲突也增加,时间复杂度增长到O(n)
Trie树存储多个具有相同前缀的键时使用较小的空间,只需要O(m)的时间复杂度,m为键长
平衡树中查找键值需要O(mlogn)的时间复杂度
Trie的结点结构
1.有根树
2.最多R个指向子节点的链接,每个链接指向数据集中的一个字母
3.布尔字段,以指定节点是对应键的结尾还是只是键前缀
class TrieNode {
// R links to node children
private TrieNode[] links;
private final int R = 26;
private boolean isEnd;
public TrieNode() {
links = new TrieNode[R];
}
public boolean containsKey(char ch) {
return links[ch -'a'] != null;
}
public TrieNode get(char ch) {
return links[ch -'a'];
}
public void put(char ch, TrieNode node) {
links[ch -'a'] = node;
}
public void setEnd() {
isEnd = true;
}
public boolean isEnd() {
return isEnd;
}
}
操作
一、插入键
通过搜索Trie树来插入一个键,从根开始搜索
1.链接存在,沿着链接移动到树的下一个子层,并继续搜索下一个键字符
2.链接不存在,创建一个新的节点,并将它与父节点的链接相连,该链接与当前的键字符匹配
到达最后一个字符,将当前节点标记为结束节点
class Trie {
private TrieNode root;
public Trie() {
root = new TrieNode();
}
// Inserts a word into the trie.
public void insert(String word) {
TrieNode node = root;
for (int i = 0; i < word.length(); i++) {
char currentChar = word.charAt(i);
if (!node.containsKey(currentChar)) {
node.put(currentChar, new TrieNode());
}
node = node.get(currentChar);
}
node.setEnd();
}
}
二、查找键
从第一个键字符开始,检查当前节点中与键字符对应的链接
1.存在链接,移动到链接后面路径中的下一个节点,继续搜索
2.不存在链接,无键字符,且当前节点标记为isEnd,返回True
否则,还有键剩余,找不到后续路径;没有键剩余,当前节点没有标记为isEnd,两种情况都返回false
class Trie {
...
// search a prefix or whole key in trie and
// returns the node where search ends
private TrieNode searchPrefix(String word) {
TrieNode node = root;
for (int i = 0; i < word.length(); i++) {
char curLetter = word.charAt(i);
if (node.containsKey(curLetter)) {
node = node.get(curLetter);
} else {
return null;
}
}
return node;
}
// Returns if the word is in the trie.
public boolean search(String word) {
TrieNode node = searchPrefix(word);
return node != null && node.isEnd();
}
}
三、查找前缀
从根遍历,知道键没有字符,或者无法继续前进,到达键末尾返回true,否则false
class Trie {
...
// Returns if there is any word in the trie
// that starts with the given prefix.
public boolean startsWith(String prefix) {
TrieNode node = searchPrefix(prefix);
return node != null;
}
}
C++简化版本
class TrieNode
{
public:
TrieNode* next[26];
bool isend;
TrieNode(){
isend = false;
memset(next,0,sizeof(next));
}
};
class trie
{
TrieNode* root;
public:
trie(){
root = new TrieNode();
}
void insert(string word){
TrieNode* cur = root;
for(int i=0;i<word.size();i++){
cout<<word[i]<<endl;
if(cur->next[word[i]-'a']==NULL){
cur->next[word[i]-'a'] = new TrieNode();
}
cur=cur->next[word[i]-'a'];
}
cur->isend = true;
}
};