前缀树
建立一个前缀树,将字符串按照顺序连接成一棵前缀树。
前缀树的每一个节点,都有一个path值表示通过了几次,end值表示在这个节点结束了几次。
每一个节点可以产生下一级节点next,next是一个26位的数组,这是对于字符串是26个英文字母的情况。
建立节点
public static class TrieNode {
public int pass;
public int end;
// TreeMap<Char, Node> 有序表可以让路按一定顺序排列
public TrieNode[] nexts;
public TrieNode() {
pass = 0;
end = 0;
nexts = new TrieNode[26]; //如果字符种类特别多怎么办? 可以换成HashTable
// HashMap<Char, Node> nexts; 存储某一个字符下级对应的节点
}
}
建立前缀树
我们需要将字符串数组中的字符串,构建前缀树,因此需要一个添加字符串进入前缀树的函数,需要一个前缀树的头节点和构造函数。
public static class Trie{
private TrieNode head;
public Trie() {
head = new TrieNode();
}
public void insert(String s) {
if (s == null) {
return;
}
char[] chs = s.toCharArray();
TrieNode node = head;
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.pass++;
}
node.end++;
}
}
查询函数
除了插入字符串的函数,还可以实现查询函数。查询函数是为了实现可以查询,前缀树中某个字符串添加过几次。那么我们只需要找到这个字符串最后一个节点的end值就可以知道这个字符串添加了几次。
除此之外,如果遇到字符串的某一个字符的节点在前缀树中么有,那说明存在的个数为0,也就是之前插入了0次还没有加入.
public int search(String word) {
if (word == null) {
return 0;
}
char[] chs = word.toCharArray();
TrieNode node = head;
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.end;
}
查询pre是多少字符串的前缀
//所有加入字符串中,有几个以pre这个字符串作为前缀的。
public int prefixNumber(String pre) {
if (pre == null) {
return 0;
}
char[] chs = pre.toCharArray();
TrieNode node = head;
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.pass;
}
删除函数
遍历这个字符串,对前缀树的沿途节点pass–,最后一个节点end–。
//删除函数
public void delete(String word) {
if (search(word) != 0) { // 先判断,里面有该字符
//删除就是沿途每一个节点的pass--,最后的end--。
char[] chs = word.toCharArray();
TrieNode node = head;
node.pass--;
int index = 0;
for (int i = 0; i < chs.length; i++) {
index = chs[i] = 'a';
if (--node.nexts[index].pass == 0) {
node.nexts[index] = null;
return; //如果是别的语言,要手动释放空间。 遍历到底,然后回来的时候析构
}
node = node.nexts[index];
}
node.end--;
}
}
这里注意C++等别的原因,需要手动释放空间的,要改一下代码。