找到B +树的中位数

时间:2013-05-11 15:55:05

标签: java algorithm

我需要实现一个B +树。

我需要创建以下方法:

  1. 插入(x) - 0(log_t(x))。
  2. 搜索 - 成功搜索 - O(log_t(x))。不成功的搜索 - O(1){有很高的可能性}
  3. 所以我开始实现Insert(x) - 每次我有一个完整的叶子我想把它分成两个分开的叶子。 一个键的键等于或低于中间键,第二个将包含值高于中值的键。

    如何在不损害运行时间的情况下找到此中位数?

    我想到了:

    1. 将每个内部节点和叶子表示为较小的B +树,但只有当树完全平衡时,中位数才是根(或根中的一个元素)。
    2. 将每个内部节点和叶子表示为双向链表。并且在插入输入时尝试获取中值键,但是输入不适用于它。
    3. 表示为数组可能会给我中间,但是当我将其拆分时,我至少需要O(n / 2)才能将键插入到新数组中。
    4. 我该怎么办?

      关于搜索,想法明智:成功和不成功搜索之间的区别在于在树叶中搜索,但我仍然需要通过树的不同键“运行”以确定密钥是否在树。那怎么可能是O(1)?

3 个答案:

答案 0 :(得分:4)

在B +树中,所有值都存储在树叶中。

请注意,您可以将每个叶子的指针添加到下一个叶子,除了标准B +树之外,您还可以获得包含所有元素的有序链接列表

现在,请注意,假设您知道此链接列表中的当前中位数是什么 - 插入/删除时您可以便宜地计算新的中位数(它可以是同一节点,下一个节点或上一个节点,没有其他选择)。
请注意,修改此指针为O(1)(尽管插入/删除本身为O(logn)

鉴于知识 - 可以缓存指向中值元素的指针,并确保在删除/插入时保留它。当您要求中位数时 - 只需从缓存中获取中位数 - O(1)


关于Unsuccessful search - O(1) {With a high likely-hood} - 这个是尖叫 bloom filters ,这是一个概率集实现,从不会出现假阴性(从来没有说过某些东西没有设置) ,但有一些误报(说某些东西在缓存中,而事实上并非如此)。

答案 1 :(得分:2)

您不需要B + -tree的中位数。您需要在要拆分的节点中使用中值键。您必须在该中值处拆分以满足每个节点具有 N / 2< = n< = N 键的条件。节点中的中间键只是中间的键,位于 n / 2 ,其中 n 中实际键的数量。节点。这就是你拆分节点的地方。计算是O(1):它不会伤害运行时。

在不叠加其他数据结构的情况下,您无法从B +树获得O(1)搜索失败时间。

答案 2 :(得分:1)

我已经发布了一个答案(并且已经删除了它),但我可能会误解,所以这里是另一种解释的答案......

如果您需要始终知道哪个项目是完整 B +树容器中的中位数,该怎么办。

正如amit所说,你可以将指针(以及你的根指针)保存到包含中位数的当前叶节点。您还可以在该叶节点中保留索引。因此,您可以通过直接关注正确的节点和项目来获得O(1)访问权限。

问题在于维持这一点。当然amit是正确的,对于每个插入,中位数也必须保持相同的项目,或者必须步骤到之前或之后的那个。如果您通过叶节点有一个链表,即使这意味着步入相邻的叶节点,也可以有效地处理。

但是,我不相信,尽管如此,确定是否或采用哪种方式,除了在中位数和插入恰好位于同一叶节点的特殊情况之外,这是微不足道的。

如果您知道完整树的大小(可以使用根指针轻松存储和维护),则至少可以确定插入前后中间项应该是哪个索引。

但是,您需要知道先前的中间项是否已将其索引向上移位 - 如果插入点位于中位数之前或之后。除非插入点和中位数恰好位于同一节点,否则这是一个问题。

Overkill方式 - 扩充B +树以支持计算项目的索引并搜索索引。其诀窍是每个节点保留其子树的叶节点中的项目总数。这可以推高一个级别,因此每个分支节点都有一个子树大小数组及其子节点指针数组。

这提供了两种解决方案。您可以使用该信息在搜索时确定插入点的索引,或者(提供节点具有父指针)您可以使用它来重新确定插入后的上一个中间项的索引。

[实际上是三个。插入后,您可以根据新的大小搜索新的中途索引,而不参考之前的中间链接。]

然而,就增加存储的数据而言,这结果是过度的。您不需要知道插入点的索引或先前的中位数 - 您可以知道插入的中位数的哪一侧。如果您知道要从根到中间项的跟踪,您应该能够在搜索插入点时跟踪它的哪一侧。因此,您只需要增加足够的信息来查找和维护该踪迹。