T r i e Trie Trie 树
欢迎关注我的公众号ACJavaBear了解更多精彩内容
1.什么是 T r i e Trie Trie 树
T r i e Trie Trie 树,又叫前缀树,也叫字典树,用于统计和保存大量的字符串。
它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较。
简而言之, T r i e Trie Trie 树是用来存储和查找字符串的一个集合。
2. T r i e Trie Trie 树的结构
如图(图片来自于百度百科)
(1) 根节点 root
(2) 子节点 TrieNode
- 该节点是否是某字符串的结尾字符
isEnd
,true
则是,否则不是 - 该节点的儿子数组
TrieNode[] son
,用于存储该节点的儿子 - 以当前节点结尾的字符串出现的次数
num
- 当前结点的值
val
(有时完全不需要)
(3) T r i e Trie Trie 树的几种常见操作
- 插入
- 查询
3. 如何用代码编写一棵 T r i e Trie Trie 树
以存储由小写字母构成的字符串的 T r i e Trie Trie 树为例。
(1) 创建一个类名为 T r i e Trie Trie
(2) 属性
-
根节点
TrieNode root
-
普通结点
TrieNode
- 属性
boolean isEnd
TrieNode[] son
int num
- 构造方法
public TrieNode(){ isEnd = false; son = new TrieNode[26]; num = 0; }
- 属性
(3) 构造方法
public Trie(){
root = new TrieNode();
}
(4) 基本操作
- 插入一个字符串
public void insert(String word){
char[] w = word.toCharArray();
TrieNode p = root;
for(char c : w){
//把'a'~'z'映射到0~25
int u = c - 'a';
if(p.son[u] == null) p.son[u] = new TrieNode();//没有子节点,创建子节点
p = p.son[u];//到子节点位置
}
p.isEnd = true;//以当前结点结尾的字符串标记为true
p.num++;//出现次数加一
}
- 查询一个字符串在集合中出现了几次
public int query(String word){
char[] w = word.toCharArray();
TrieNode p = root;
for(char c : w){
int u = c - 'a';
if(p.son[u] == null) return 0;//没有该节点,直接返回0
p = p.son[u];
}
if(p.isEnd == true) return p.num;//是以此节点为结尾,返回出现次数
return 0;
}
具体代码
public static class Trie{
public TrieNode root;
public Trie(){
root = new TrieNode();
}
public class TrieNode{
boolean isEnd;
TrieNode[] son;
int num;
public TrieNode(){
isEnd = false;
son = new TrieNode[26];
num = 0;
}
}
public void insert(String word){
char[] w = word.toCharArray();
TrieNode p = root;
for(char c : w){
int u = c - 'a';
if(p.son[u] == null) p.son[u] = new TrieNode();
p = p.son[u];
}
p.isEnd = true;
p.num++;
}
public int query(String word){
char[] w = word.toCharArray();
TrieNode p = root;
for(char c : w){
int u = c - 'a';
if(p.son[u] == null) return 0;
p = p.son[u];
}
if(p.isEnd == true) return p.num;
return 0;
}
4.练习题
$LeetCode 208. 实现 Trie (前缀树) $
https://leetcode-cn.com/problems/implement-trie-prefix-tree/
题解如下
class Trie {
TrieNode root; //根节点
class TrieNode{//普通结点类
boolean isEnd;
TrieNode[] son;
public TrieNode(){
isEnd = false;
son = new TrieNode[26];
}
}
/** Initialize your data structure here. */
public Trie() {
root = new TrieNode();
}
/** Inserts a word into the trie. */
public void insert(String word) {
if(word != null && word.length() != 0){
char[] w = word.toCharArray();
TrieNode p = root;
for(char c : w){
int u = c - 'a';
if(p.son[u] == null) p.son[u] = new TrieNode();
p = p.son[u];
}
p.isEnd = true;
}
}
/** Returns if the word is in the trie. */
public boolean search(String word) {
if(word == null || word.length() == 0) return false;
TrieNode p = root;
char[] w = word.toCharArray();
for(char c : w){
int u = c - 'a';
if(p.son[u] == null) return false;
p = p.son[u];
}
if(p.isEnd) return true;
return false;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String word) {
if(word.length() == 0 || word == null) return false;
TrieNode p = root;
char[] w = word.toCharArray();
for(char c : w){
int u = c-'a';
if(p.son[u] == null) return false;
p = p.son[u];
}
return true;
}
}
/**
* Your Trie object will be instantiated and called as such:
* Trie obj = new Trie();
* obj.insert(word);
* boolean param_2 = obj.search(word);
* boolean param_3 = obj.startsWith(prefix);
*/