参考链接:
https://segmentfault.com/a/1190000008877595
双数组字典树(DATrie)详解及实现 | Ragty の Blog
双数组Trie树(DoubleArrayTrie)Java实现-码农场
之前node实现方式
开场白:
看了好几天了,感觉自己菜的不行,懂了之后写代码又发现很多问题,把一个树放到数组里也不是那么容易的,但想想还是先总结一版,后面再优化。
双数组实现Trie:
就是用两个数组维护一棵树,通过计算能找到对应的子节点。
双数组有哪些:
base数组,用于记录偏移量,check数组,用于记录上一个节点的数组下标,用于验证。
关键点思考:
如何创建双数组结构的Trie
1 base 中的值:base中存储的是偏移量,偏移量加上下一个字符的char或者编号,就是下一个base节点的下标
2 如何找叶子节点?:通过base中的下标,加上下一个查找字符的char值或者唯一编号,就能得到叶子节点的下标。
3 如何避免解决base冲突:当构建的时候,偏移量+字符char找到的下一个叶子节点下标很有可能已经被占用了,这个时候通过改变偏移量(自增+1)来继续寻找直到找到。
4 多个叶子节点:多个叶子节点构建的时候需要保证不同的字符char+偏移量 对应的base数组下标都是空的才可以,有任何一个位置被占了都要偏移量+1来继续寻找,所以构建的时候按层构建Tire前缀树,需要传入构建前缀树的词是按照每个字符排序过的。
5 如何表达结束:当base中的值为负值,代表当前有一个词结尾了,查询的时候用于判断。
6 check数组:check数组中存的是上一个父节点base的下标,因为通过偏移量+字符char的方式,不能保证命中的就是当前父节点的子节点,需要check来验证一下
如何查找
循环要查找的字符,根据每个字符+base[i],来计算下一个节点的地址,并根据下一个节点check来检查,当base[i]的值为 负值,说明有一个词结尾,就输出,直到最后找不到叶子节点或者词结束。
缺点,只能找出 查找字符前面的词,后面的叶子节点关联不出来,因为需要有字符才能计算后面的叶子节点。
双数组Trie的优点:查找匹配时间复杂度0(m) m是要查找字符的长度
双数组Trie的缺点:
1 构建时间比较长,因为会有冲突再找的过程
2 数组浪费比较严重不可控,有可能还要扩容
3 不好添加删除节点,添加很有可能会有冲突,导致当前层所有子节点的位置都要重算,包括当前层下面所有叶子节点,严重有可能要重新构建整棵树。
总结:在网上看了很多帖子,也看了几版代码,还是没有吃透,自己写的时候发现很多问题,所以继续学习吧,关键点先总结下。