Trie,又经常叫前缀树,字典树等等.实现思路如下
颜色为黑色的表示只是字符串中间的字符,为蓝色的表示是字符串末尾的那个字符,空白那个是树根节点.每个节点的意义实际上就是根,节点到这个结点所经过的每个字符组成的字符串.故而图中这个树实际上意味着已存在字符串"","to","tea","ted","ten","a","i","in","inn"
代码
public class Trie {
private int SIZE = 26;
private TrieNode root;// 字典树的根
class TrieNode // 字典树节点
{
private int num;// 有多少单词通过这个节点,即由根至该节点组成的字符串模式出现的次数
private TrieNode[] son;// 所有的儿子节点
private boolean isBlue;// 是不是最后字符
private char val;// 节点的值
TrieNode() {
num = 1;
son = new TrieNode[SIZE];
isBlue = false;
}
}
Trie() // 初始化字典树
{
root = new TrieNode();
}
// 建立字典树
public void insert(String str) // 在字典树中插入一个单词
{
if (str == null || str.length() == 0) {
return;
}
TrieNode node = root;
char[] letters = str.toCharArray();// 将目标单词转换为字符数组
for (int i = 0, len = str.length(); i < len; i++) {
int pos = letters[i] - 'a';
if (node.son[pos] == null) // 如果当前节点的儿子节点中没有该字符,则构建一个TrieNode并复值该字符
{
node.son[pos] = new TrieNode();
node.son[pos].val = letters[i];
} else // 如果已经存在,则将由根至该儿子节点组成的字符串模式出现的次数+1
{
node.son[pos].num++;
}
node = node.son[pos];
}
node.isBlue = true;
}
// 计算单词前缀的数量
public int countPrefix(String prefix) {
if (prefix == null || prefix.length() == 0) {
return -1;
}
TrieNode node = root;
char[] letters = prefix.toCharArray();
for (int i = 0, len = prefix.length(); i < len; i++) {
int pos = letters[i] - 'a';
if (node.son[pos] == null) {
return 0;
} else {
node = node.son[pos];
}
}
return node.num;
}
// 在字典树中查找一个完全匹配的单词.
public boolean has(String str) {
if (str == null || str.length() == 0) {
return false;
}
TrieNode node = root;
char[] letters = str.toCharArray();
for (int i = 0, len = str.length(); i < len; i++) {
int pos = letters[i] - 'a';
if (node.son[pos] != null) {
node = node.son[pos];
} else {
return false;
}
}
// 走到这一步,表明可能完全匹配,可能部分匹配,如果最后一个字符节点为末端节点,则是完全匹配,否则是部分匹配
return node.isBlue;
}
public static void main(String[] args) {
Trie tree = new Trie();
String[] dictionaryData = { "hello", "student", "computer", "sorry", "acm", "people", "experienced", "who",
"reminds", "everyday", "almost" };
String[] txt = { "computer", "hello", "acm", "computer", "experienced", "computer", "hello", "eclipse",
"student", "hello", "hello", "hello", "hello", "experienced" };
// 构建字典
for (String str : dictionaryData) {
tree.insert(str);
}
Map<String, Integer> countMap = new HashMap<String, Integer>();
for (int i = 0; i < txt.length; i++) {
String lineTxt = txt[i];
if (tree.has(lineTxt)) {
if (countMap.containsKey(lineTxt)) {
countMap.put(lineTxt, countMap.get(lineTxt) + 1);
} else {
countMap.put(lineTxt, 1);
}
} else {
System.out.println(lineTxt + "不在字典中!");
}
}
for (String s : countMap.keySet()) {
System.out.println(s + "出现的次数" + countMap.get(s));
}
}
}
数组字典树
针对只有ascii码的字典树,我们可以采用数组的方式如下
作用
1.字符串检索
事先将已知的一些字符串(字典)的有关信息保存到trie树里,查找另外一些未知字符串是否出现过或者出现频率。
2.词频统计
有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
3.排序
Trie树是一棵多叉树,只要先序遍历整棵树,输出相应的字符串便是按字典序排序的结果。
4.字符串最长公共前缀
5.字符串搜索的前缀匹配
trie树常用于搜索提示。如当输入一个网址,可以自动搜索出可能的选择。当没有完全匹配的搜索结果,可以返回前缀最相似的可能。