【问题标题】:A particular problem with btree insertionbtree插入的一个特殊问题
【发布时间】:2011-03-17 11:17:30
【问题描述】:

我一直在slady.net 玩非常酷的 btree 小程序。我无法理解特定行为。看看这个起始状态:

alt text http://www.freeimagehosting.net/uploads/db2931c7da.jpg

通过插入以下序列达到此特定状态:10、15、30、16、70、1、9、27、45、50、55。

我的问题是当我在序列中插入下一个值 65 时 [45, ] 节点会发生什么。

alt text http://www.freeimagehosting.net/uploads/3b70c1d302.jpg

[55,70] 节点将被 65 分割,作为中间值,65 将向上移动,然后也分割 [30,50] 节点。我的问题是:为什么 [45, ] 节点最终成为 [30, ] 节点的子节点?它的 parent 最初有 3 个孩子,最左边和最右边成为新的单独节点。 45 介于这些值之间,似乎它也可以在 [65, ] 节点下结束......为什么?

【问题讨论】:

  • 由于使用的特定算法对我们来说是不透明的,它只提供黑盒测试。将 [69, 66] 添加到你的最终树对我来说是违反直觉的。
  • 问题的标题是“btree 插入”......我不知道我怎么能更具体。

标签: algorithm insertion b-tree


【解决方案1】:

一张图片胜过千言万语;一部动画价值一百万:

http://constellationmedia.com/~funsite/static/btree-insert-animation.gif

这里要注意的关键是,当中心节点 50 被拉上时,它必须丢弃它的右孩子,因为它太低了。但是,65 需要一个新的左子节点,因此 50 将 45 交给 65。50 现在需要一个新的右子节点,并且包含 65 的节点需要成为子节点,因此它将新形成的 65 取而代之。

这里展示了 B-tree 插入规则(其中最大节点大小为 4 个项目,5 个子节点):

http://constellationmedia.com/~funsite/static/btree-insertion-rules.png

xr 将不存在,并且如果您要插入叶子(您先执行此操作),则无关紧要。但是,如果你必须将一个节点分成两半,那么新的x 是你拉出的中心项,新的xrx 的右孩子。

【讨论】:

  • 嗯,显然,您的动画似乎值 69 个字。 ;P +1,很好的答案。 ;)
  • 哇,你居然为我的案子制作了动画?我希望我可以多次投票!
  • @BaconBits:我托管的服务器不再存在。当我得到改变时,我将不得不挖掘图像。感谢您(再次)提醒我。
【解决方案2】:

每个节点总是有 n+1 个子节点,其中 n 是该节点中的键数。

在分裂之前,[30, 50] 节点有两个键和三个孩子,正如预期的那样。当你拆分它时,你最终会得到一个 [30, -] 节点和一个 [65, -] 节点(并将 50 提升一个级别)。

在下一层,您有(以前存在的)[16, 27] 和 [45, -],以及新拆分的 [55, -] 和 [70, -] 节点。

您有两个父节点和四个子节点。每个父母必须有两个孩子,因为它只有一个钥匙。因此,给定排序规则,[45, -] 必须是 [30, -] 的子节点,否则 (1) [30, -] 将没有足够的子节点,并且 (2) [65, -] 会有太多的孩子。 [编辑 - 对于一个节点来说不是非法的太多,但分裂应该是平衡的]。

Will A 也是正确的。这是在拆分中间层节点时选择上推50键的结果,但这并不是真正的选择。拆分生成 [-, -] 和 [50, 65] 推高 30,或 [30, 50] 和 [-, -] 推高 65 将违反每个节点必须至少半满的规则。

【讨论】:

    【解决方案3】:

    将 45 节点作为第二个图中 65 节点的子节点是没有意义的,因为最右边的分支用于值 > 50(基于根节点最右边的值) - 所以 45 必须进入某处的中间分支。

    【讨论】:

    • 是的,我同意......当我手工完成时,我把它放在了正确的位置。问题是“没有意义”很难编码!到目前为止,其他一切都是简单的规则(拆分完整节点,拆分上升等)......
    • 你研究过 B-tree 插入规则吗?我建议查看 B-tree 规则的一些描述,而不是从 applet 派生逻辑。
    • @dicroce - 基本事实是 btree 很繁琐。当使用较大的节点时,它们会变得更糟,您希望通过在相邻兄弟节点之间重新分配键来延迟节点拆分和节点合并,这也意味着父节点中的键 between 两个兄弟节点将改变也。我发现根据所有项目的有序数组进行更多思考会有所帮助,用括号来分隔节点,例如 [[9] 15 [30] 50 [65]] (您的示例的前两层) - 但只有到一个点。
    • @diocre - B+ 树更容易。所有项目都在叶子节点中,它们都处于相同的深度。分支节点只保存“子树摘要”——例如标准的“子树中的最低键”,以支持基于键的搜索。叶节点通常形成一个列表,因此您根本不必触摸分支节点即可进行顺序访问。并且拆分、合并和重新分配更容易一些,因为这些项目都在叶节点中——通过分支节点向上传播键和其他摘要更新相对简单。当然,分支节点仍然会拆分/合并/等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-30
    • 1970-01-01
    • 1970-01-01
    • 2016-11-24
    • 2015-06-06
    • 2018-11-12
    相关资源
    最近更新 更多