「这是我参与2022首次更文挑战的第 5 天,活动详情查看:2022首次更文挑战」。
《系统日报》持续关注分布式系统、AI System,数据库、存储、大数据等相关领域文章。每天以摘要的形式精选不超过三篇系统文章分享给大家。 如果你有好文章推荐,或者有其他任何想法,欢迎在 Articles Weekly Repo 提 issue。
一种的自适应式的基数 Trie
来源:www.the-paper-trail.org/post/art-pa…
摘要:除了哈希表和查找树,Trie 树是另一种常被提起的 KV 索引结构,当然它也比较另类:插入时,会将每个 Key 展开到树的路径中。由此带来诸多好处:
- 树的深度只和 Key 的长度有关,而和 Key 的数量无关。
- 又称“前缀树”,对于前缀查找特别方便。
但坏处自然也很明显:
- 每个节点有很多空指针,有大量空间被浪费。
- Key 的字符集受限,比如要求 Key 只能由 ASCII 码组成。
由于其特点决定,这俩互为因果,如果不限制字符集,空指针会更多。
为了减少空间浪费,有人提出了一些压缩算法。比如基数 Trie( radix tries),又称紧凑前缀树。基本思想是通过减少树的节点,从而减少空指针。解决方法是在树的路径上下功夫,如果某个树的路径(包含多个节点)没有分叉,就将其压缩为一个节点,即允许一个节点存储多个字符。
图源:medium.com/basecs/comp… Trie 的很棒的文章
这个压缩方法的代价是,在插入或者删除 key 时,需要处理节点的展开与合并。但,等等,你说我都懂,这和**基数(Radix)**有毛线关系?答案是,Radix Trie 会将所有的 Key 进行二进制展开,以二进制的每个位作为单个字符作为 Trie 树中的字符,进行插入。想想这么做有什么好处?
- 减少了分叉数(每个节点只有两个分叉 0 和 1),从而减少了无用指针浪费。
- 增大了共同前缀的概率,被拉长的路径,正好可以用路径压缩来缩短。
而 ART(Adaptive Radix Tree) 走的是另外一条路,不是在垂直方向(树的纵深方向)下功夫,而是在水平方向(每个节点的扇出,fan-out)做文章。经典 Trie 需要为字符集中的每个字符保留一个指针,不管其是否真的会存在。ART 正是抓住这一点,提出了一种自适应的 Trie 结构,首先来看看其核心数据结构——Trie 树节点:
union Node {
Node4* n4;
Node16* n16;
Node48* n48;
Node256* n256;
}
看到该数据结构,我们就大概猜出他要干什么了,即在分叉较少时,用小分叉节点;在分叉较大时,使用较大分叉节点。换个角度想,这就类似将经典的 Trie 树种指针从固定数组,换到了可变数组()。当然,每个节点的查找时间,也从 O(1) 换到了 O(lgn),不过考虑到 n 一般比较小,也可近似认为 O(1) == O(lgn)。此外,还可以控制可变的档位,可以针对性的对 cache 进行优化,可以去博客或者原论文中详细研读一下。