看了两天,这个双数组是怎么存储trie树的也没看明白。你去搜各种文章吗,一个人一个说法,就是没一个写明白的。试图看了一下原始作者的代码(又是日本人),
komiya-atsushi/darts-javagithub.com实在没看下去,全是n,p,i的字母变量,所以决定放弃,我可不较这个劲,而且也没啥用途。有谁不服的,可以来给我讲讲,毕恭毕敬地听。你也可以看看HanLP作者写的教程,也是不怎么样。
双数组Trie树(DoubleArrayTrie)Java实现-码农场www.hankcs.com1. trie树
先来说trie树,trie树的树结构很好理解,大部分文章也都能说明白,这里只简要说明。trie树是按照排序后的词典存储的。这里引用HanLP的图了。
显然,树的每i行对应于词典中词语的第i个字,因此在存储前需要对词典中的单词进行排序。具有相同前缀的词语会在一棵子树上。
2. 双数组trie树
这里对于双数组trie树的原理不进行阐述,原因前边已经说过,它的想法其实很简单,就是用两个数组来存储一棵trie树,这种存储方法不仅节省内存空间而且检索词语的速度也非常快。放一个HanLP中的示例在下边,这个示例我直接用的darts-java。
package darts;
import darts.DoubleArrayTrie;
import java.io.*;
import java.util.*;
public class DemoDoubleArrayTrie {
public static void main(String[] args) throws IOException {
// 读入词典
BufferedReader reader = new BufferedReader(new FileReader("./data/small.dic"));
String line;
List<String> words = new ArrayList<String>();
Set<Character> charset = new HashSet<Character>();
while ((line = reader.readLine()) != null) {
words.add(line);
// 制作一份码表debug
for (char c : line.toCharArray()) {
charset.add(c);
}
}
reader.close();
// 输出汉字以及对应的汉字编码
System.out.println("字典词条:" + words.size());
{
String infoCharsetValue = "";
String infoCharsetCode = "";
for (Character c : charset) {
// 读出1个汉字
infoCharsetValue += c.charValue() + " ";
// 读出该汉字的编码
infoCharsetCode += (int) c.charValue() + " ";
}
infoCharsetValue += 'n';
infoCharsetCode += 'n';
System.out.print(infoCharsetValue);
System.out.print(infoCharsetCode);
}
// 构建双数组trie树
DoubleArrayTrie dat = new DoubleArrayTrie();
System.out.println("是否错误: " + dat.build(words));
System.out.println(dat.toString());
// 公共前缀匹配
List<Integer> integerList = dat.commonPrefixSearch("一举成名天下知");
for (int index : integerList) {
System.out.println(words.get(index));
}
}
}
输出结果
字典词条:6
一 成 知 胶 万 动 天 下 名 能 举
19968 25104 30693 33014 19975 21160 22825 19979 21517 33021 20030
是否错误: 0
darts.DoubleArrayTrie@7852e922
一举
一举成名
一举成名天下知
如果有哪个小伙伴想挑战读这段代码,彻底弄明白到底是怎么用两个数组来存储trie树,那就直接下载darts-java来看吧,我估计全国也没几个认真看过这个代码的,也或者看了也没看懂。招聘面试的也没人敢提,直到为啥不,因为他自己都讲不明白。这就叫日本人都嚼的没味的东西,中国人依然搞不明白。
准备撸串去喽,6点准时开始。