这是一个trie的想法,目的是相当简单,但也相当有效和通用。它从任意字节序列映射到32位整数。(小的非负整数存储效率更高。负整数是效率最低的。)
输入字符串将映射到字节序列。如果trie是为适当的字符集族构建的,则可以直接使用不变字符串,或者我们可以将EBCDIC输入映射到ASCII(同时小写用于区分大小写的匹配)。
对于泰语DBBI,每个U+0E00..U+0EFF都可以映射到其低字节。
对于CJK DBBI,我们可以使用UTF-16BE或它的一个轻微变体。对于一般的Unicode字符串(例如时区名称),我们可以设计一个简单的编码,将可打印的ASCII映射为单个字节,Unihan和Hangul以及其他一些范围映射为每个字符两个字节,其余映射到每个字符三个字节。(我们也可以将其用于CJK DBBI,以减少此类“转换器”的数量。)或者,我们使用 UCharsTrie公司对于这些。
随附示例代码。
请参阅 UCharsTrie公司兄弟姐妹页面了解更多详细信息。BytesTrie和UCharsTrie结构几乎相同,只是UCharsTrie使用的单位更少、更大。
另请参见 字符串到值映射示例集的BytesTree图.
BytesTrie和UCharsTrie设计为字节序列化/UChar-serialized,用于简单的平台交换。
紧凑:小值和跳转增量应该用几个字节编码。这需要可变长度的编码。
每个值/增量的长度在前一个节点或其自身的引导单元中编码。这样可以有效地跳过值,并且在读取可变长度值时需要进行范围检查的单位更少。
值较小的节点以单个单位编码。
线性匹配节点无需选择即可匹配一系列单元。
分支机构
分支存储相对增量以“跳转”到以下节点。小增量以单个单位编码;编码增量比编码绝对偏移有效得多。
可变宽度值使得在分支节点上进行二进制搜索不可行。因此,对于线性搜索,带有(键、值)对列表的分支被限制为短列表长度。
对于大型分支,分支节点包含一个单元,用于向左(小于)或向右(大于或等于)分支。这将二进制搜索编码到数据结构中。
在每个节点的末尾(最终值节点除外),将继续与下一个节点进行匹配,而不是使用另一个跳转到其他位置。
每个分支头节点编码分支的长度(要从中选择的单位数)。split-branch和list-branch子节点没有节点头。相反,该代码跟踪分支的剩余长度,将每个分支边的长度减半,并在列表分支子节点中倒计时。
列表分支子节点的最大长度是固定的,即序列化数据格式的一部分,不能进行兼容更改。此常数用于分支代码中,以决定是拆分小于/大于或等于还是遍历键值对列表。
此常数必须至少为3,以便split-branch子节点的长度至少为4,以便以下列表分支节点的长度最少为2,并且可以使用do-while循环而不是while环。(保存一个长度检查。)
我探索了一种替代方法,只使用长度为1的分支节点,然后使用最后一个匹配单元继续匹配。它速度快,但也大得多。这样的分支大约是键值对列表大小的两倍。如果平均列表分支长度为n,则分支具有(length/n)-1个分支子节点。这个实验对应于n=1。
美国石油学会
该API简单且低级。在核心,next(unit)“转动曲柄”,基本上返回一个2位的结果,编码matches()(这个单元继续一个匹配的序列)、hasNext()(另一个单元可以继续一个匹配的序列)和hasValue()(到目前为止,单元是一个匹配的字符串)。
可以在低级函数的基础上构建处理不同输入的高级函数(例如,动态规范化单元),并提供各种功能(例如,最长匹配、startsWith、从文本中的某个点查找所有匹配…),而不会使API混乱或引入更多依赖项。
下一个(unit)函数在值节点上停止,而不是对值进行解码,从而在请求值之前节省时间(通过getValue())。接下来的下一个(unit2)调用将跳过值节点。
有足够的API用于各种用途,包括匹配/映射整个字符串,查明前缀是否只属于具有相同值的字符串,获取从某个点可以继续的所有单元,以及获取所有(字符串、值)对。这应该能够支持查找、使用缩写进行解析、分词等。
“快速”构建器代码很简单。构建器进行构建时,在编写序列化表单之前不需要使用trie结构,也不需要提供任何trie运行时API。
有一个生成“小”trie的构建器代码,试图避免写入重复的节点。当节点的整棵树都是相同的,并且至少有一棵树是通过“跳跃”增量到达的,该增量可以“跳跃”到这样一棵树之前编写的序列化时,这是可能的。