什么是Trie树
Trie树,又叫字典树、前缀树(Prefix Tree)、单词查找树 或 键树,是一种多叉树结构。
Trie树的优缺点
优点
- 插入和查询的效率很高,都为O(m)的时间复杂度,其中 m 是待插入/查询的字符串的长度。
- 关于查询,会有人说 hash 表时间复杂度是O(1)不是更快?但是,哈希搜索的效率通常取决于 hash 函数的好坏,若一个坏的 hash 函数导致很多的冲突,效率并不一定比Trie树高。
- Trie树中不同的关键字不会产生冲突。
- Trie树只有在允许一个关键字关联多个值的情况下才有类似hash碰撞发生。
- Trie树不用求 hash 值,对短字符串有更快的速度。通常,求hash值也是需要遍历字符串的。
- Trie树可以对关键字按字典序排序。
缺点
- 当 hash 函数很好时,Trie树的查找效率会低于哈希搜索。
- 空间消耗比较大。
Trie树的应用
- 字符串检索
- 词频统计
- 字符串排序
- 前缀匹配
- 作为其他数据结构和算法的辅助结构,如后缀树,AC自动机等。
Trie树的java实现
思想
- 多岔树结构。
- 连接线是字符。
- 节点有两个属性,一个是字符经过的次数,一个是字符结尾的次数。 比如加入字符串 abc ab ack.
图解
代码
public static class Node{
public int pass;
public int end;
public HashMap<Integer, Node> nexts;
public Node(){
pass =0;
end =0;
nexts = new HashMap<>();
}
}
public static class Trie{
private Node root;
public Trie(){
root = new Node();
}
public void insert(String word){
if (word == null){
return;
}
char[] chars = word.toCharArray();
Node node = root;
node.pass++;
int index = 0;//路径
for (int i= 0; i<chars.length;i++){
index = (int) chars[i];
if (!node.nexts.containsKey(index)){//下一层的路径中不包括
node.nexts.put(index,new Node());
}
node = node.nexts.get(index);//当前节点
node.pass++;//当前节点++
}
//循环结束后,说明单词已经遍历完
node.end++;
}
public void delete(String word){
if (serch(word)!=0){
Node node = root;
int index = 0;
char[] chars = word.toCharArray();
for (int i=0;i<chars.length;i++){
index = (int)chars[i];
if (--node.nexts.get(index).pass == 0){
node.nexts.remove(index);//删除节点,防止内存泄露
}
node = node.nexts.get(index);
}
node.end--;
}
}
//word 这个单词之前加入了几次
private int serch(String word) {
if (word == null){
return 0;
}
char[] chars = word.toCharArray();
Node node = root;
int index = 0;
for (int i= 0; i<chars.length;i++) {
index = (int) chars[i];
if (!node.nexts.containsKey(index)){
return 0;
}
node = node.nexts.get(index);
}
return node.end;//有几个结尾,就加入了几次
}
//所有加入的字符串中,有几个是以pre 这个字符串作为前缀的
public int prefixNumber(String pre){
if (pre == null){
return 0;
}
char[] chars = pre.toCharArray();
Node node = root;
int index =0;
for (int i=0;i<chars.length;i++){
if (!node.nexts.containsKey(index)){
return 0;
}
node = node.nexts.get(index);
}
return node.pass;//有几个单词经过 就有几个
}
}