字节字符串

这是一个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,用于简单的平台交换。

    • 紧凑:小值和跳转增量应该用几个字节编码。这需要可变长度的编码。

    • 每个值/增量的长度在前一个节点或其自身的引导单元中编码。这样可以有效地跳过值,并且在读取可变长度值时需要进行范围检查的单位更少。

    • 值较小的节点以单个单位编码。

    • 线性匹配节点无需选择即可匹配一系列单元。

    • 分支机构

      • 分支存储相对增量以“跳转”到以下节点。小增量以单个单位编码;编码增量比编码绝对偏移有效得多。

      • 可变宽度值使得在分支节点上进行二进制搜索不可行。因此,对于线性搜索,带有(键、值)对列表的分支被限制为短列表长度。

      • 对于大型分支,分支节点包含一个单元,用于向左(小于)或向右(大于或等于)分支。这将二进制搜索编码到数据结构中。

        • 最初,我在分支子节点中也有一个等边,但这大大降低了匹配速度(在一种情况下为9%),而对序列化大小没有明显帮助(在这种情况下为0.2%)。

      • 在每个节点的末尾(最终值节点除外),将继续与下一个节点进行匹配,而不是使用另一个跳转到其他位置。

      • 每个分支头节点编码分支的长度(要从中选择的单位数)。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的构建器代码,试图避免写入重复的节点。当节点的整棵树都是相同的,并且至少有一棵树是通过“跳跃”增量到达的,该增量可以“跳跃”到这样一棵树之前编写的序列化时,这是可能的。