通过学习自定义字典树,了解字典树这一数据结构。
之前的二分搜索树(二叉树)、堆(完全二叉树)、线段树(平衡二叉树)都是基于二叉树。而字典树是一种多叉树。
如果有n个条目,使用树结构查询的时间复杂度为O(log n),如果有100万个条目(2^20),log n 大约为20; 而使用Trie(字典树)的时间复杂度与有多少条目无关,为O(w),w为查询单词的长度(大多数单词的长度不超过10)。
Trie的局限性:空间问题。
实践:前缀搜索 参考: LeetCode之208. 实现 Trie (前缀树)
实践:简单的模式匹配 参考:LeetCode之211. 添加与搜索单词 - 数据结构设计
自定义字典树(Trie):
package Trie;
import java.util.TreeMap;//java提供的TreeMap底层是红黑树
public class Trie {
/**
* 内部类
*
* @author xiaohau
*
*/
private class Node{
public boolean isWord;//指示当前node是否为一个完整的单词
public TreeMap<Character,Node> next;//保存字符及下一个节点信息
public Node(boolean isWord) {
this.isWord=isWord;
next=new TreeMap<>();
}
public Node() {
this(false);
}
}
private Node root;//根节点
private int size;//字典树中单词数量
/**
* 无参构造函数,初始化根节点
*/
public Trie() {
root=new Node();
size=0;
}
/**
* 返回字典树中单词的数量
* @return
*/
public int getSize() {
return size;
}
/**
* 向Trie中添加一个新的单词word
* @param word
*/
public void add(String word) {
Node cur=root;//指向当前头结点
//遍历单词每个字符,若节点中不存在,则添加,负责,跳过该结点,继续判断
for(int i=0;i<word.length();i++) {
char c=word.charAt(i);
if(cur.next.get(c)==null) {
cur.next.put(c, new Node());
}
cur=cur.next.get(c);
}
//修改当前结点为一个完整的单词
if(!cur.isWord) {
cur.isWord=true;
size++;
}
}
/**
* 查询单词word是否在Trie中
* @param word
* @return
*/
public boolean contains(String word) {
Node cur=root;
for(int i=0;i<word.length();i++) {
char c=word.charAt(i);
if(cur.next.get(c)==null) {
return false;
}
cur=cur.next.get(c);
}
return cur.isWord;
}
/**
* 查询是否在Trie中有单词以prefix为前缀
* 注:整个单词也是整个单词的前缀
* @param prefix
* @return
*/
public boolean isPrefix(String prefix) {
Node cur=root;
for(int i=0;i<prefix.length();i++) {
char c=prefix.charAt(i);
if(cur.next.get(c)==null) {
return false;
}
cur=cur.next.get(c);
}
return true;
}
}