给出字符串,如“abc”
从头结点开始,依次检查,有没有走向a的路,如果没有,就新建出来,a作为路上的值(不是结点的值),如果有的话,就复用
在字符串的结尾处的结点的值+1,表示有一个是以该字符串结尾的
1.可以查是否某个字符串是以某个字符串为前缀的
2.还可以查 添加了几次该前缀 (有多少字符串是以该结点结尾的)
3.还可以查有多少个字符串是以字符串作为前缀的(前缀的词频是多少)(有多少字符串到达过该结点)
插入字符串:public void insert(String str)
删除字符串:public void delete(String str)
在前缀树中查询字符串出现的次数:public int search(String str)
在前缀树中查询以str字符串为前缀的个数:public int prefixNumber(String str)
public class TrieTree {
//前缀树的结构
public static class TrieNode{
//表示扫过当前结点多少次
public int path;
//表示以当前结点结尾的次数
public int end;
//表示当前结点的下一个结点(从a-z) 同时,数组中对应的位置就是a-z字母的顺序
// 如果想表示其他类型的,可以使用HashMap nexts;
// key表示的是边的ASCII码,value表示对应的下一个结点
public TrieNode[] nexts;
public TrieNode(){
path = 0;
end = 0;
nexts = new TrieNode[26];
}
}
public static class Trie{
//前缀树的头结点 为空
private TrieNode root;
public Trie(){
root = new TrieNode();
}
/**
* 将一个字符串加入前缀树,即向前缀树中添加路径和结点,
* 首先检查前缀树中是否含有当前结点,
* 如果存在的话,则将其路径上的path++,end++,
* 如果不存在某几个结点的话,则创建出来
* @param str
*/
public void insert(String str){
if(str == null || str.length() == 0) return;
char[] ch = str.toCharArray();
TrieNode trieNode = root;
for(int i = 0; i < ch.length; i++){
int index = ch[i] - 'a';
//该元素不存在,则创建出来
if(trieNode.nexts[index] == null){
trieNode.nexts[index] = new TrieNode();
}
trieNode = trieNode.nexts[index];
trieNode.path++;
}
trieNode.end++;
}
/**
* 删除指定字符串对应在前缀树中的路径
* 在前缀树中查找,然后依次将其path-1,
* 当path==0时,直接将其置为null即可(后面的结点都可以不要了)
* @param str
*/
public void delete(String str){
if(str == null || str.length() == 0) return;
char[] ch = str.toCharArray();
TrieNode trieNode = root;
for(int i = 0; i < ch.length; i++){
int index = ch[i] - 'a';
if(--trieNode.nexts[index].path == 0){
trieNode.nexts[index] = null;
return;
}
trieNode = trieNode.nexts[index];
}
trieNode.end--;
}
/**
* 查询一个字符串在前缀树中出现了多少次
* 如果一路下来都存在,则返回end中的值,
* 如果过程中含有不存在的值,则返回0
* @param str
* @return
*/
public int search(String str){
if(str == null || str.length() == 0) return 0;
char[] ch = str.toCharArray();
TrieNode trieNode = root;
for(int i = 0; i < ch.length; i++){
int index = ch[i] - 'a';
if(trieNode.nexts[index] == null) return 0;
trieNode = trieNode.nexts[index];
}
return trieNode.end;
}
/**
* 查找以str为前缀的字符有多少
* 即查找以str为路径的path是多少
* @param str
* @return
*/
public int prefixNumber(String str){
if(str == null || str.length() == 0) return 0;
char[] ch = str.toCharArray();
TrieNode trieNode = root;
for(int i = 0; i < ch.length; i++){
int index = ch[i] - 'a';
if(trieNode.nexts[index] == null) return 0;
trieNode = trieNode.nexts[index];
}
return trieNode.path;
}
public static void main(String[] args) {
Trie trie = new Trie();
System.out.println(trie.search("zuo"));
trie.insert("zuo");
System.out.println(trie.search("zuo"));
trie.delete("zuo");
System.out.println(trie.search("zuo"));
trie.insert("zuo");
trie.insert("zuo");
trie.delete("zuo");
System.out.println(trie.search("zuo"));
trie.delete("zuo");
System.out.println(trie.search("zuo"));
trie.insert("zuoa");
trie.insert("zuoac");
trie.insert("zuoab");
trie.insert("zuoad");
trie.delete("zuoa");
System.out.println(trie.search("zuoa"));
System.out.println(trie.prefixNumber("zuo"));
}
}
}