定义
用了两个第三方jar包,lombok 和 hutool,可自行替换
@Data
public class TrieNode {
private final int SIZE = 26;
/**
* 有多少个单词通过这个节点
*/
private int num;
/**
* 所有的儿子节点
*/
private TrieNode[] son;
/**
* 是不是结束节点
*/
private boolean isEnd;
/**
* 节点值
*/
private char value;
/**
* 是否有儿子节点
*/
private boolean hasSon;
public TrieNode() {
num = 1;
son = new TrieNode[SIZE];
isEnd = false;
hasSon = false;
}
}
操作类(插入,前缀查找,查找所有)
/**
* 字典树工具
*
* @author wangql
* @date 2021/02/24
*/
public class TrieTreeUtil {
/**
* 字典树插入字符串
*
* @param node 节点
* @param str str
*/
public static void insert(TrieNode node, String str) {
if (StrUtil.isBlank(str)) {
return;
}
char[] chars = str.toCharArray();
for (char val : chars) {
// 当前字符对应的数字位置
int positionNum = val - 'a';
// 获取儿子
TrieNode[] sons = node.getSon();
if (sons == null) {
sons = new TrieNode[26];
}
if (sons[positionNum] == null) {
// 设置当前位置有儿子节点
node.setHasSon(true);
sons[positionNum] = new TrieNode();
sons[positionNum].setValue(val);
} else {
// 当前节点的前缀数量+1
sons[positionNum].setNum(sons[positionNum].getNum() + 1);
}
node = sons[positionNum];
}
node.setEnd(true);
}
/**
* 计算单词前缀的数量
*
* @param prefix 前缀
* @return int
*/
public static int calculateNumberOfWordPrefixes(TrieNode tree, String prefix) {
if (StrUtil.isBlankIfStr(prefix)) {
return -1;
}
char[] chars = prefix.toCharArray();
for (char val : chars) {
// 获取位置
int positionNum = val - 'a';
TrieNode[] sons = tree.getSon();
if (sons == null || sons[positionNum] == null) {
return 0;
} else {
tree = sons[positionNum];
}
}
return tree.getNum();
}
/**
* 获取具有指定前缀的单词
*
* @param tree 树
* @param prefix 前缀
* @return {@link List<String>}
*/
public static List<String> getWordWithSpecifiedPrefix(TrieNode tree, String prefix) {
if (StrUtil.isBlankIfStr(prefix)) {
return null;
}
char[] chars = prefix.toCharArray();
for (char val : chars) {
int positionNum = val - 'a';
TrieNode[] son = tree.getSon();
if (son != null && son[positionNum] != null) {
tree = son[positionNum];
} else {
return null;
}
}
return preTraverse(tree, prefix, new ArrayList<String>());
}
/**
* 遍历某节点下的所有单词
*
* @param tree 树
* @param prefix 前缀
* @param list 列表
* @return {@link List<String>}
*/
public static List<String> preTraverse(TrieNode tree, String prefix, List<String> list) {
if (tree.isHasSon()) {
TrieNode[] son = tree.getSon();
for (TrieNode child : son) {
if (child != null) {
list = preTraverse(child, prefix + child.getValue(), list);
}
}
}
// 只有单词才输出
if (tree.isEnd()) {
list.add(prefix);
System.out.println(prefix);
}
return list;
}
/**
* 匹配词
*
* @param tree 树
* @param str 字符串
* @return boolean
*/
public static boolean matchWord(TrieNode tree, String str) {
if (StrUtil.isBlankIfStr(str)) {
return false;
}
char[] chars = str.toCharArray();
for (char val : chars) {
int positionNum = val - 'a';
TrieNode[] sons = tree.getSon();
if (sons != null && sons[positionNum] != null) {
tree = sons[positionNum];
} else {
return false;
}
}
// 判断是否为 end 节点
return tree.isEnd();
}
/**
* 获取所有单词
*
* @param tree 树
* @param str 字符串
* @param list 列表
* @return {@link List<String>}
*/
public static List<String> getAllWords(TrieNode tree, String str, List<String> list) {
if(tree.isHasSon()) {
TrieNode[] sons = tree.getSon();
for (TrieNode son : sons) {
if(son != null){
getAllWords(son, str+son.getValue(), list);
}
}
}
if(tree.isEnd()){
list.add(str);
}
return list;
}
}
测试
/**
* 测试
*
* @author wangql
* @date 2021/02/24
*/
public class Test {
public static void main(String[] args) {
TrieNode root = new TrieNode();
// 插入
TrieTreeUtil.insert(root, "dog");
TrieTreeUtil.insert(root, "egg");
TrieTreeUtil.insert(root, "art");
TrieTreeUtil.insert(root, "cat");
TrieTreeUtil.insert(root, "cats");
TrieTreeUtil.insert(root, "cap");
TrieTreeUtil.insert(root, "captain");
TrieTreeUtil.insert(root, "caps");
// 计算前缀开头的单词数量
System.out.println(TrieTreeUtil.calculateNumberOfWordPrefixes(root, "c"));
System.out.println(TrieTreeUtil.calculateNumberOfWordPrefixes(root, "cap"));
// 获取前缀开头的单词
List<String> cap = TrieTreeUtil.getWordWithSpecifiedPrefix(root, "cap");
System.out.println(cap);
// 遍历所有单词
List<String> list = TrieTreeUtil.getAllWords(root, "", new ArrayList<String>());
System.out.println("所有单词:"+list);
System.out.println("是否完全匹配单词ca:"+TrieTreeUtil.matchWord(root, "ca"));
}
}