关键点:
1、节点类的构建,通过一个数组记录下一个节点及路径
2、注意path==0、end==0的含义
//字典树、前缀树的实现
/*是一种树形结构,优点是利用字符串的公共前缀来节约存储空间
* */
class TrieNode{
public int path;//表示有多少个单词共用这个节点
public int end;//表示有多少个单词以这个节点结尾
public TrieNode[] map;
//key表示该节点的一条字符路径,value表示字符路径指向的节点
public TrieNode() {
path = 0;
end = 0;
map = new TrieNode[26];
}
}
class Trie{
private TrieNode root;
public Trie() {
root = new TrieNode();
}
//添加word,可重复添加
public void insert(String word) {
if(word == null) {
return;
}
char[] chs = word.toCharArray();
TrieNode node = root;
int index = 0;//记录下一个节点
for(int i = 0;i < chs.length;i++) {
index = chs[i]-'a';
if(node.map[index] == null) {
node.map[index] = new TrieNode();
}
node = node.map[index];
node.path++;
}
node.end++;
}
//查询word是否在trie树中
public boolean search(String word) {
if(word == null) {
return false;
}
char[] chs = word.toCharArray();
TrieNode node = root;
int index = 0;
for(int i = 0;i < chs.length;i++) {
index = chs[i]-'a';
if(node.map[index] == null) {
return false;
}
node = node.map[index];
}
//没有单词通过最后一个节点
if(node.end == 0) {
return false;
}
return true;
}
//删除word,如果word添加过多次,仅删除一个
public void delete(String word) {
if(search(word)) {
char[] chs = word.toCharArray();
int index = 0;
TrieNode node = root;
for(int i = 0;i < chs.length;i++) {
index = chs[i]-'a';
if(node.map[index].path-- == 1) {
node.map[index] = null;//该路径没有单词走过
}
node = node.map[index];
}
node.end--;
}
}
//返回以字符串pre为前缀的单词数量
public int prefixNumber(String pre) {
if(pre == null) return 0;
TrieNode node = root;
int index = 0;
char[] chs = pre.toCharArray();
for(int i = 0;i < chs.length;i++) {
index = chs[i]-'a';
if(node.map[index] == null) {
return 0;
}
node = node.map[index];
}
return node.path;
}
}