【问题标题】:What invariant do RRB-trees maintain?RRB 树维护什么不变量?
【发布时间】:2012-12-10 00:54:48
【问题描述】:

Relaxed Radix Balanced Trees(RRB-trees)是不可变向量(用于 Clojure 和 Scala)的泛化,具有“有效恒定”的索引和更新时间。 RRB 树保持高效的索引和更新,但也允许高效的连接 (log n)。

作者以我难以理解的方式呈现数据结构。我不太确定每个节点维护的不变量是什么。

在第 2.5 节中,他们描述了他们的算法。我认为他们确保索引到节点只需要在基数搜索之后进行额外的线性搜索步骤。我不明白他们是如何得出额外步骤的公式的,我想也许我不确定每个变量的含义(特别是“总共 p 个子树分支”)。

RRB-tree 连接算法是如何工作的?

【问题讨论】:

  • 我对它们的表示感到困惑的一点是,对于所有向量大小,every 节点不可能是度数-m 或度数-(m-1)。考虑例如 m=8 和长度为 80 的向量。我假设右脊椎允许具有任意度数,但如果他们在论文中说我错过了它。
  • @BenYlvisaker 询问是否允许 RRB 向量的右脊柱具有任意度数。两年后:-),这是一个答案。是:RRB 树的所有节点都应包含在 (m - e) 和 m 子节点之间,其中 e 是允许的弹性因子 - except 用于树的最右边的脊椎,其可以安全地包含少于 m - e 子节点。 (对于 32 路向量,e = 2 是一个不错的选择)。 Bagwell 和 Rompf 在他们的论文中没有提到这一点,但 Jean Niklas L'orange 在他的master's thesis about RRB trees 中确实提到了这一点。

标签: algorithm scala data-structures clojure tree


【解决方案1】:

他们确实在第 2.4 节中描述了一个不变量“但是,如前所述 B-Trees 节点不利于基数搜索。相反,我们选择了 允许节点大小在m 之间的初始不变量 和m - 1。这定义了一个平衡树家族,从 众所周知的 2-3 棵树、3-4 棵树和(对于 m=32)31-32 棵树。这 invariant 保证平衡并实现基数分支搜索 大多数情况。有时需要几步线性搜索 基数搜索后找到正确的分支。 更高级别所需的额外步骤会增加。”

看看他们的公式,他们似乎已经计算出存储在子树中的最大和最小可能值数量。两者之间的差异是一个点下的最大和最小值之间的最大可能差异。如果将其除以插槽下方的值数,则当您确定要查看哪个插槽以查看它是否包含您正在搜索的索引时,您将获得最大的插槽数。

【讨论】:

  • 我的阅读是,这是他们选择作为垫脚石的初始算法。第 2.5 节说他们使用约束较少的方法。我想也许我应该像你说的那样通过计算存储值的最大和最小数量来推导他们的公式。
【解决方案2】:

@mcdowella 是正确的,这就是他们所说的放松节点。但是,如果您要拆分和连接节点,从 mm-1 的范围意味着您有时必须调整到 m- 1 (m-2?) 个节点,以便从节点中添加或删除单个元素。这似乎非常低效。我认为它们的意思是在 m 和 (2 m) - 1 之间,因为这允许节点在它们变得太大时被分成 2 个,或者当它们变得太大时将 2 个节点合并为一个太小而无需更改第三个节点。因此,论文中的“2 m”中缺少“2”是一个错字。 Jean Niklas L’orange's masters thesis 支持我。

此外,所有严格节点的长度都相同,必须是 2 的幂。原因是 Rich Hickey 的 Clojure PersistentVector 中的优化。好吧,我认为重要的是打包剩下的所有严格节点(稍后会详细介绍),这样您就不必猜测要下降树的哪个分支。但是能够移位和位掩码而不是除法是一个很好的奖励。我没有在宽松的 Scala Vector 上计时 get() 操作,而是在 relaxed Paguro vector is about 10x slower than the strict one 上计时。因此,它尽一切努力尽可能严格,如果您在 0 处重复插入,甚至会产生 2 个严格级别。

他们的树也有一个均匀的高度——所有的叶子节点到根的距离都相等。我认为,如果放松的树必须在彼此之间的一层内,它仍然可以工作,尽管不确定这会给你带来什么。

松弛节点可以有严格的子节点,反之则不行。

严格节点必须从左侧(低索引)无间隙地填充。任何非完整的 Strict 节点必须位于树的右侧(高索引)边缘。如果您在焦点或尾部追加,所有严格的叶节点总是可以满的(更多内容见下文)。

您可以通过搜索Paguro implementation 中的 debugValidate() 方法来查看大部分不变量。那不是他们的论文,但主要是基于它。实际上,Scala implementation 中的“显示”变量也没有在论文中提及。如果你要研究这些东西,你可能想先好好看看 Clojure PersistentVector,因为 RRB 树里面有一个。它与 RRB Tree 的两个区别是:1. RRB Tree 允许“松弛”节点;2. RRB Tree 可能有“焦点”而不是“尾巴”。焦点和尾部都是小缓冲区(可能与严格的叶节点大小相同),不同之处在于焦点可能会定位到向量的最后插入/附加到的任何区域,而尾部始终位于末尾(PerSitentVector 只能追加,不能插入)。这两个区别是允许 O(log n) 任意插入和删除,加上 O(log n) split() 和 join() 操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-23
    • 2011-05-20
    相关资源
    最近更新 更多