本文主要是对double-array实际实现时的一些概念和逻辑进行自己的解释, 有误请指点. [email protected]
常用的高效查询检索数据结构
double-array用途: 文本分词, 模糊匹配检索, 精确匹配检索
网上很多资料, 可以自己搜索, 基本原理的介绍不是本文的重点
http://blog.jqian.net/post/trie.html
本文也是建立在你已经了解了基本原理的基础上, 所以请首先了解下上面的内容, 或者如下原文:
http://linux.thai.net/~thep/datrie/datrie.html
double-array是由 triple-array 进行空间压缩和优化得来的, 那么是基于什么原理分析出三数组可以压缩为双数组的呢?
* 数据如何表示: 要构建的数据被分割为多个字符, 比如 a-z, 每个字符都进行数据编号, 这个编号就是作为寻找内存空间时的增量偏移来使用, 不同的字符编号不同
* 中文如何表示: 理论上中文可以用穷举的方式进行编号, 比如1-65535, 但是实际上一个中文字符是被当做两个字节看待的, 这样就可以把中文的字符编码降维到 ascii码的数量级 也就是说中文的编码其实就是用字节的ascii码来代替的, 这样对双字节字符的拆分不会影响其检索时的准确问题和召回问题, [体会工业实现的妙处吧]
* base数组: base数组的 "下标" 就是有限状态机里的状态标号; base[i] 位置存储的数值 是状态i的偏移基址, 偏移基址是用于该状态转移到后续状态时寻找合适的可用内存空间使用的.
* next数组: 存储的是当前状态经过某个输入转移后的状态, 比如 a接收c到达另外一个状态, 那么 next[ ad基址偏移 + code(c) ] = 状态c
* check数组: 是检查某个状态的前一个状态是什么.
* 基址偏移: 这个算法的重点是理解 base数组里存储的值的含义, 也就是当前状态的基址偏移, 基址偏移是表示当前状态在接受后续输入时寻找转移状态的一个基准.
也就是说后续状态的位置 = 基址偏移 + 输入编码 , 而输入编码是永远不会改变和调整的, 出现冲突的时候只能调整基址偏移来寻找合适的位置.
和上面的原因类似, 按深度构建的时候需要用递归和栈的原理来实现, 而树结构很自然的具备递归和栈的特性.
树结构只是在构建数据的时候使用的辅助数据结构,
构建完毕后树就可以销毁了, 检索的时候也不需要树的结构了