Trie,又经常叫前缀树,字典树等,
基本性质
1,根节点不包含字符,除根节点意外每个节点只包含一个字符。
2,从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
3,每个节点的所有子节点包含的字符串不相同
优点:
可以最大限度地减少无谓的字符串比较,故可以用于词频统计和大量字符串排序。
跟哈希表比较:
1,最坏情况时间复杂度比hash表好
2,没有冲突,除非一个key对应多个值(除key外的其他信息)
3,自带排序功能(类似Radix Sort),中序遍历trie可以得到排序。
缺点:
内存消耗非常大
应用场景:
(1) 字符串检索
(2)文本预测、自动完成,see also,拼写检查
(3)词频统计
(4)排序
(5)字符串最长公共前缀
(6)字符串搜索的前缀匹配
(7) 作为其他数据结构和算法的辅助结构
递归实现样例:
定义树
class TrieNode{
// 节点内容
char word;
// 子节点
Map<Character,TrieNode> childMap;
// 是否字符串结尾
Boolean isEnd= true;
public TrieNode(){
this.isEnd=false;
this.childMap = new HashMap<>();
}
}
新增
public void recursionAdd(TrieNode root,String word) {
add(root, word, 0);
}
/**
* 递归写法调用方法实现递归添加
*
* @param node 传入要进行添加的节点
* @param word 传入要进行添加的单词
*/
public void add(TrieNode node, String word, int index) {
if (!node.isEnd && index == word.length()) {
node.isEnd = true;
}
if (word.length() > index) {
char addLetter = word.charAt(index);
if (node.childMap.get(addLetter) == null) {
node.childMap.put(addLetter, new TrieNode());
}
// 基于已经存在的字符进行下个字符的递归查询
add(node.childMap.get(addLetter), word, index + 1);
}
}
删除
public void deleteWord(TrieNode root , String word){
if(!recursionContains(root, word)){
return;
}
delete(root,word,0);
}
/**
* 删除Trie中word递归写法(1,叶子节点删除;2,公用节点设置结尾标示为false)
*
* @param node
* @param word
* @param index
* @return
*/
public Boolean delete(TrieNode node,String word,int i){
Boolean isDel = false;
// 字符串最后一个字节
if(i == word.length()){
if(CollectionUtils.isEmpty(node.childMap)){
node = null;
isDel = true;
}else{
node.isEnd = false;
isDel = false;
}
}
else{
char local = word.charAt(i);
if(delete(node.childMap.get(local),word,i+1)){
if(node.isEnd){
isDel = false;
}else if(!CollectionUtils.isEmpty(node.childMap)){
isDel = false;
}else{
node = null;
isDel = true;
}
}else{
isDel = false;
}
}
return isDel;
}
查询
public boolean recursionContains(TrieNode root,String word) {
return contains(root, word, 0);
}
/**
* 查询word中是否在Trie中递归写法
*
* @param node
* @param word
* @param index
* @return
*/
private boolean contains(TrieNode node, String word, int index) {
if (index == word.length()) {
return node.isEnd;
}
char c = word.charAt(index);
if (node.childMap.get(c) == null) {
return false;
} else {
return contains(node.childMap.get(c), word, index + 1);
}
}