结构
Trie树,又叫字典树、前缀树(Prefix Tree)、单词查找树或键树,是一种多叉树结构。如下图:
基本性质:
①根节点不包含字符,除根节点外的每一个子节点都包含一个字符。
②从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
③每个节点的所有子节点包含的字符互不相同。
④从第一字符开始有连续重复的字符只占用一个节点,比如上面的body,boy和boat,中重复的单词o只占用了一个节点。
应用:
①前缀匹配
②字符串检索
③词频统计
④字符串排序
代码实现:
一、针对a-z的字符串
//假设所有的输入都是由小写字母 a-z 构成的。
//所有输入均为非空字符串。
class Trie {
//根节点
private TrieNode root;
public Trie() {
//初始化根节点
root = new TrieNode();
}
public void insert(String word) {
TrieNode node = this.root;
//遍历
for(char c: word.toCharArray()){
if(node.children[c-'a'] == null){
node.children[c-'a'] = new TrieNode();
}
node = node.children[c-'a'];
}
node.item = word;
}
public boolean search(String word) {
TrieNode node = this.root;
//遍历
for(char c:word.toCharArray()){
if(node.children[c-'a'] == null){
return false;
}
node = node.children[c-'a'];
}
return node.item.equals(word);
}
public boolean startsWith(String prefix) {
TrieNode node = this.root;
//遍历
for(char c: prefix.toCharArray()){
if(node.children[c-'a'] == null){
return false;
}
node = node.children[c-'a'];
}
return true;
}
//定义 前缀树节点 的结构
class TrieNode{
//孩子节点,分别记录26个字母
TrieNode[] children = new TrieNode[26];
//当前的节点(叶子节点)对应的单词
String item = "";
}
}
public class Test {
public static void main(String[] args) {
String s1 = "boat";
String s2 = "body";
String s3 = "boy";
String s4 = "dog";
String s5 = "dad";
String s6 = "a";
Trie trie = new Trie();
trie.insert(s1);
trie.insert(s2);
trie.insert(s3);
trie.insert(s4);
trie.insert(s5);
trie.insert(s6);
System.out.println(trie.search(s5));
System.out.println(trie.startsWith("bc"));
System.out.println(trie.startsWith("bo"));
}
}
true
false
true
二、针对字符串
public class TestTrie {
public static void main(String[] args) {
Tries tries = new Tries();
String strs[]={"我","我们","我们是","我们是好人","a","abc","ab"};
for(int i=0;i<strs.length;i++) {
insertNode(strs[i], tries);
}
System.out.println(searchNode("我们是",tries));
System.out.println(searchNode("ab",tries));
System.out.println(startWithPrefix("我们",tries));
}
public static boolean insertNode(String str,Tries head) {
Tries cur = head;
for(char c: str.toCharArray()){
if(!cur.children.containsKey(c)) {
cur.children.put(c, new Tries());
}
cur = cur.children.get(c);
}
cur.item = str;
return false;
}
public static boolean searchNode(String str,Tries head) {
Tries cur = head;
for(char c: str.toCharArray()){
if(!cur.children.containsKey(c)) {
return false;
}
cur = cur.children.get(c);
}
return cur.item.equals(str);
}
public static boolean startWithPrefix(String str,Tries head) {
Tries cur = head;
for(char c: str.toCharArray()){
if(!cur.children.containsKey(c)) {
return false;
}
cur = cur.children.get(c);
}
return true;
}
}
class Tries{
String item = "";
HashMap<Character, Tries> children = new HashMap<>();
}
前缀树和DFA算法的理念很像,而且实现比我之前写的DFA算法的还要简短和好理解,感觉DFA那篇的实现不是很好,前缀树完全可以实现。