前缀树
前缀树prefix tree trie
1)单个字符串中,字符从前到后的加到一棵多叉树上
2)字符放在路上,节点上有专属的数据项(常见的是pass和end值)
3)所有样本都这样添加,如果没有路就新建,如有路就复用
4)沿途节点的pass值增加1,每个字符串结束时来到的节点end值增加1
可以完成前缀相关的查询
例子
设计一种结构。用户可以:
1)void insert(String str) 添加某个字符串,可以重复添加,每次算1个
2)int search(String str) 查询某个字符串在结构中还有几个
- void delete(String str) 删掉某个字符串,可以重复删除,每次算1个
4)int prefixNumber(String str) 查询有多少个字符串,是以str做前缀的
前缀树路的实现方式
1)固定数组实现
2)哈希表实现
package com.lzf2.class06;
//前缀树
public class TrieTree {
private Node root;
public TrieTree() {
root = new Node();
}
/**
* 添加某个字符串,可以重复添加,每次算1个
*
* @param str 要添加的字符串
*/
public void insert(String str) {
if (str == null) {
return;
}
Node currNode = root;
root.pass++;
char[] chars = str.toCharArray();
//找路
for (char c : chars) {
int path = c - 'a';
if (currNode.nexts[path] == null) {//没有这条路
currNode.nexts[path] = new Node();
}
currNode = currNode.nexts[path];
currNode.pass++;
}
currNode.end++;
}
/**
* 查询某个字符串在结构中还有几个
*
* @param str 要查询的字符串
* @return 该字符串有几个
*/
public int search(String str) {
if (str == null || str.length() == 0) {
return 0;
}
char[] chars = str.toCharArray();
Node currNode = root;
for (char c : chars) {
int path = c - 'a';
if (currNode.nexts[path] == null) {
return 0;
}
currNode = currNode.nexts[path];
}
return currNode.end;
}
/**
* 删掉某个字符串,可以重复删除,每次算1个
*
* @param str 要删除的字符串
*/
public void delete(String str) {
//1.该字符串是否存在
if (search(str) == 0) {
return;
}
Node currNode = root;
currNode.pass--;
//2.转成字符数据
char[] chars = str.toCharArray();
for (char c : chars) {
int path = c - 'a';
if (--currNode.nexts[path].pass == 0) {//后面没有其他的字符串了
currNode.nexts[path] = null;
return;
}
currNode = currNode.nexts[path];
}
currNode.end--;
}
/**
* 查询有多少个字符串,是以str做前缀的
*
* @param str 要查询的字符串前缀
* @return 以该str为前缀的个数
*/
public int prefixNumber(String str) {
if (str == null || str.length() == 0) {
return 0;
}
Node currNode = root;
char[] chars = str.toCharArray();
for (char c : chars) {
int path = c - 'a';
if(currNode.nexts[path] == null){
return 0;
}
currNode = currNode.nexts[path];
}
return currNode.pass;
}
private class Node {
int pass;//路过的记录数
int end;//结束的记录数
Node[] nexts;//路
public Node() {
pass = 0;
end = 0;
this.nexts = new Node[26];//26个英文字母
}
}
}