但是要判断字符串是否已经加过:
在节点还保存一个信息:是否以这个节点为结尾?计数(加入几次这个字符串)。
如果问:给一个字符串,有多少字符串以它作为前缀?
解决方法:加一个数据项(每一个节点被划过多少次)
前缀树:代价极低!效率非常高,和样本量没关系,和自身样本长度有关。
TrieNode代码:
public static class TrieNode{
public int path; //经过多少次
public int end; //以该节点结尾的的字符串有几个
public TrieNode[] next;
public TrieNode(){
path = 0;
end = 0;
next = neww TrieNode[26]; //a-z 26条可能路径;如果其他的用map来做路径
}
}
Trie前缀树:
public static class Trie{
private TrieNode root;
public Trie(){
root = new TrieNode();
}
public void insert(String word){
if(word==null){
return null;
}
char[] chs = word.toCharArray();
TrieNode node = root;
int index = 0;
for(int i = 0; i<chs.length;i++){
index = chs[i] - 'a';
if(node.nexts[index]==null){
node.nexts[index]=new TrieNode();
}
node = node.nexts[index];
node.path++;
}
node.end++;
}
}
查询:
public int search(String word){
if(word==null){
return 0;
}
char[] chs = word.toCharArray();
TrieNode node = root;
int index = 0 ;
for(int i = 0; i<chs.length;i++){
index = chs[i] - 'a';
if(node.nexts[index]==null){
return 0; //没有插入过,返回0
}
node = node.nexts[index];
}
return node.end;
}
删除:
public void delete(String word){
if(search(word)!=0){
char[] chs = word.toCharArray();
TrieNode node = root;
int index = 0;
for(int i = 0; i<chs.length;i++){
index = chs[i] - 'a';
if(--node.nexts[index].path==0){
node.nexts[index]=null;//之后不需要沿途减了,底下直接为空,JVM可以释放,C++的话还得找到以下的节点,析构
return 0;
}
node = node.nexts[index];
}
node.end--;
}
}
查找前缀的数目
public int preixNumber(String pre){
if(pre==null){
return 0;
}
char[] chs = pre.toCharArray();
TrieNode node = root;
int index = 0;
for(int i = 0; i<chs.length;i++){
index = chs[i] - 'a';
if(node.nexts[index]==null){
return 0;
}
node = node.nexts[index];
}
return node.path;
}