1. Trie树的定义:Trie树也叫字典树,单词查找树,是一种多叉树。专门处理字符串 查询每个条目的时间复杂度,和树中一共多少条目无关,其时间复杂度为O(w),w为所查询单词的长度,大多数单词的长度小于10(优势)。
2. Trie树的实现:
//定义Trie树又称字典树 字典树是专门对字符串或字符进行操作的一种树 因此我们在定义是不需要再定义泛型
/*
* 字典树的存储特点:根节点不存放数据 且字典树属一种多叉树 每个节点存放的是字符串或字符的一个字母
* 并且对字符串进行的是有序的存储 树中不会存放重复的首字母
* 我们这里的字典树的节点是一个映射 键 指的是字符串或字符的字母
* 值 指的是当前字母的节点的孩子节点(孩子节点为当前字母再字符串或字符中的下一个字母)
* 相当于是映射中嵌套映射
*/
public class Trie {
//定义节点 节点包含三部分
private class Node{
public boolean isWord; //表示当前字母的组成是否是一个完整的单词
public int count; //表示当前单词出现的次数
public AVLTreeMap<Character, Node> children; //表示当前字母的映射
public Node() {
this(false);
}
public Node(boolean isWord) {
this.isWord = isWord;
count = 0;
children = new AVLTreeMap<Character, Node>();
}
}
private Node root; //表示trie树的根节点
private int size; //表示trie中完整单词的个数 不包括重复单词
public Trie() {
root = new Node();
size = 0;
}
//获取trie中完整单词的个数 不包括重复单词
public int size() {
return size;
}
//获取指定单词在trie树中出现的次数
/*
* 首先定义一个游标 从trie树的根节点开始
* 遍历单词的每一个字母 判断当前节点的映射中是否包含该字母
* 如果不包含则返回0 表示trie树中没有指定单词
* 反之更新游标 使游标指向当前字母的值
* 值 指的是当前字母的节点的孩子节点(孩子节点为当前字母再字符串或字符中的下一个字母)
* 遍历字符串或字符结束后 判断当前是否是一个完整的单词 如果是返回当前节点的count
* 如果不是(比如时一个前缀等) 返回0
*/
public int count(String word) {
Node cur = root;
for(int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if(!cur.children.contains(c)) {
return 0;
}
cur = cur.children.get(c);
}
if(cur.isWord) {
return cur.count;
}else {
return 0;
}
}
//向trie中添加指定单词
/*
* 首先定义一个游标 从trie树的根节点开始
* 遍历单词的每一个字母 判断当前节点的映射中是否包含该字母
* 如果不包含就将该字母添加到映射中(该字母就为映射中的键 而值表示当前字母的节点的孩子节点)
* 更新游标 使游标指向当前字母的值
* 值 指的是当前字母的节点的孩子节点(孩子节点为当前字母再字符串或字符中的下一个字母)
* 遍历字符串或字符结束后 判断当前字母的组成是否是一个完整的单词即isWord是否为false
* 如果是false 就将当前节点的isWord置为true trie中完整单词的个数(不包括重复单词)加一
* 反之则表示trie树中已经有该单词 则该单词数量加一
*/
public void put(String word) {
Node cur = root;
for(int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if(!cur.children.contains(c)) {
cur.children.put(c, new Node());
}
cur = cur.children.get(c);
}
if(!cur.isWord) {
cur.isWord = true;
size++;
cur.count = 1;
}else {
cur.count++;
}
}
//判断trie树中是否包含指定单词
/*
* 首先定义一个游标 从trie树的根节点开始
* 遍历单词的每一个字母 判断当前节点的映射中是否包含该字母
* 如果不包含则返回false 表示没有指定单词
* 反之更新游标 使游标指向当前字母的值
* 值 指的是当前字母的节点的孩子节点(孩子节点为当前字母再字符串或字符中的下一个字母)
* 遍历字符串或字符结束后 返回节点的isWord
*/
public boolean contains(String word) {
Node cur = root;
for(int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if(!cur.children.contains(c)) {
return false;
}
cur = cur.children.get(c);
}
return cur.isWord;
}
//判断trie树中是否包含指定前缀
/*
* 首先定义一个游标 从trie树的根节点开始
* 遍历单词的每一个字母 判断当前节点的映射中是否包含该字母
* 如果不包含则返回false 表示没有指定前缀
* 反之更新游标 使游标指向当前字母的值
* 值 指的是当前字母的节点的孩子节点(孩子节点为当前字母再字符串或字符中的下一个字母)
* 遍历字符串或字符结束后 返回true 表示trie树中包含指定前缀
*/
public boolean isPrefix(String prefix) {
Node cur = root;
for(int i = 0; i < prefix.length(); i++) {
char c = prefix.charAt(i);
if(!cur.children.contains(c)) {
return false;
}
cur = cur.children.get(c);
}
return true;
}
}