简介
Trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。——摘自维基百科
基本性质
简单来说Trie是利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较。它的基本性质可以归纳为:
- 根节点不包含字符,除根节点意外每个节点只包含一个字符
- 从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串
- 每个节点的所有子节点包含的字符串不相同
Trie的实现
下面的代码简单的实现了Trie这种数据结构。通过isWord来标注从根节点到当前节点形成的字符串是否是一个单词。
public class Trie {
private Node root;
private class Node {
private boolean isWord;
private Map<Character, Node> nodeMap;
private Node() {
this.isWord = false;
this.nodeMap = new HashMap<>();
}
}
public Trie() {
root = new Node();
}
public void add(String word) {
if (word == null || "".equals(word)) {
throw new IllegalArgumentException("word is empty.");
}
Node currentNode = root;
for (int i = 0; i < word.length(); i++) {
char charAt = word.charAt(i);
if (currentNode.nodeMap.get(charAt) == null) {
currentNode.nodeMap.put(charAt, new Node());
}
currentNode = currentNode.nodeMap.get(charAt);
}
currentNode.isWord = true;
}
public boolean contains(String word) {
if (word == null || "".equals(word)) {
throw new IllegalArgumentException("word is empty.");
}
Node currentNode = root;
for (int i = 0; i < word.length(); i++) {
char charAt = word.charAt(i);
if (currentNode.nodeMap.get(charAt) == null) {
return false;
}
currentNode = currentNode.nodeMap.get(charAt);
}
return currentNode.isWord;
}
}