有效算法在内存中交叉m个有序集?

时间:2012-11-26 17:29:13

标签: database data-structures

假设我们有 m 有序集,我们希望找到他们的交叉点

我们应该将哪些数据结构用于有序集,哪种算法最有效?

同样的问题: Algorithm for N-way merge

看来文献很多。因此,一个更好的问题是: 有哪些好的实施?

2 个答案:

答案 0 :(得分:1)

您可以创建带有父节点链接的二叉树,并实现交集/联合的经典算法:

  1. iterA设置为树的最左侧(最小)节点(即,从最左侧的分支下降到叶子)。
  2. iterB设置为有序集的第一个(最小)节点(如果使用有序数组实现,或者如果是树,则设置为最左侧节点)。
  3. 通过比较iterAiterB指向的项目进行分支
    • 如果更低:联合产品和提前iterA
    • 如果等于:产生联合项目和交叉项目并推进iterAitemB
    • 如果更大:产生联合项目并提前iterB
  4. 重复,直到其中一个迭代器无法前进
  5. 可从其他迭代器访问的其余项目作为联合项目生成
  6. 二进制树迭代器的推进:

    • 如果当前节点有正确的子节点下降到它并尽可能下降到它的最左边的子节点。收获该项目。
    • 如果节点有父母提升,并在我们从右孩子上升时重复这一点。收获该项目。
    • 否则:树的所有项目已经产生(收集结束)。

    <强>更新 如果您知道您的有序集(由iterB走过)比树小得多,您可以使用更复杂的交叉算法:

    1. 最初将iterB设置为有序集的开头(较低的值)。
    2. iterA设置为值为iterB的最小上限的节点。
    3. 通过比较iterAiterB指向的项目进行分支
      • 如果等于:交汇的产量项目。
    4. itemB提升到下一个值。
    5. iterA开始,将itemB提升到itemA的最小值上限。
    6. 重复,直到itemB通过所有有序集合。
    7. 从特定节点前进到最小上限的位置是:

      • 如果当前节点的值小于目标
        • 通过步行每个节点的右子女来找到右孩子的上限
        • 如果该分支的最右边节点低于目标:从右子节点移动并从该节点重新启动时,提升到父节点。
        • 从我们找到上限的节点
        • 查找第一个最左边的子项值小于目标值
          • 如果未找到:该分支的最左侧叶子是最小上限
          • 从该节点重新启动(更准确地说,将使用遍历最左侧和最右侧节点缩小边界的子算法。)

      搜索绑定的主要思想是缩小上限和下限(“ - ”被忽略的节点,“...”是新的搜索范围):

      for B < X < A
          U
         / \-
        L
      -/ \...
      
      for A < X < B
        L
      -/ \
          U
      .../ \-
      

答案 1 :(得分:0)

这只是一个草图:请帮助我改进它。

此解决方案将基于使用二进制搜索将搜索限制为n / 2 ^ i每个元素的元素数量,我将使用高效的数据结构来记住下一个的比较号。

首先要注意的是,只有当搜索的间隔与(子)树的间隔非常匹配时,平衡二叉树才能很好地执行二分搜索。

接受二进制搜索的其他 2结构是数组跳过列表。 该数组对于插入和删除效率很低,因此跳过列表似乎是最佳选择。

我们需要 m大小为64的数组,它将包含每个数组的每个数组的元素,这些元素在二进制搜索中进行比较,按执行比较的顺序插入。< /强>

我们还需要一个双链表,其中将插入二进制搜索中使用的所有集合中的所有元素。 使用跳过列表可以最大限度地减少所需的比较次数。

基本理念是这个。

  1. 我们使用二进制搜索搜索每个集合中的最小元素。
  2. 在每个二进制搜索步骤中,我们在集合的数组中添加新元素 并在双链表中。
  3. 是否存在共同的最小元素。
  4. 我们删除双链表中的最小元素。新搜索将从集合的二进制搜索数组中的前一个元素开始,并将使用距离之前的一半距离。 我们使用数组中先前的二进制搜索元素将新搜索限制为最小的已知间隔。
  5. 继续1。