【问题标题】:Merging two binary max heaps in which all the elements in one heap is greater than all the elements in the other?合并两个最大二进制堆,其中一个堆中的所有元素都大于另一个堆中的所有元素?
【发布时间】:2018-04-03 07:23:08
【问题描述】:

我遇到了这个编程面试问题,但我不确定我的答案是否正确。我无法找到这个问题的正确答案。问题来了,

令 H1 和 H2 是两个(二进制)最大堆,具有 n1 和 n2 个元素 分别。如果 H1 中的每个元素都大于 H1 中的每个元素 H2,设计一种算法,将这两个堆合并为一个(二进制) O(n2) 时间内的最大堆(假设 H1 和 H2 都足够大 保存 n1 + n2 个元素)

所以,我在想,既然 H1 中的每个元素都大于 H2 中的每个元素,那么我们可以将合并的最大堆存储在 H1 中。所以,我们所要做的就是简单地从 H2 中获取第一个元素,在 H2 的数组中的位置 0 处,然后将该元素插入 H1,附加到 H1 数组的末尾,使其成为 H1 中的叶子。我们可以对 H2 中的每个元素持续执行此操作。我想一旦我们开始将 H2 中的元素作为子元素添加到 H2 的元素中,那么我们将不得不开始检查该子元素是否小于父元素,如果不是,我们交换它们。我假设由于添加一个元素,而不调用 heapify,并且在必要时进行交换会给我们带来 O(n2) 的复杂性。

那么,我的解决方案准确吗?如果没有任何帮助将不胜感激。 如果我的解决方案的任何部分不清楚,请告诉我,以便我澄清。

【问题讨论】:

  • 感觉是准确的。但是我创建了一个案例,您需要进行多次交换。考虑到 H1 相对于 H2 非常小;这意味着您几乎需要对一个元素进行 log(n2) 交换(H1:[100]、H2[25 8 24 3 7 10 23 2 1 6 5 4 9 12 22])。然而,它应该是非常罕见的。如果我们能证明这种情况会非常罕见,那么你是对的:)
  • 那么我的算法复杂度实际上是 O(n2 + log(n2)) 吗?我在计算复杂性方面没有太多经验,所以我不确定。那还是 O(n2) 吗?
  • 老实说,我现在不确定:(
  • @selecii44:可能的错误数量随着您要合并的堆的大小(即 n2)而增加。定位要交换的节点将是一个 O(n2) 操作,并且修复它们将花费 O(log n2) 每个。解决方案是在 O(n2) 中重新排列整个 n2 堆。这使得整个操作 O(2*n2),被认为是 O(n2)。

标签: algorithm data-structures heap


【解决方案1】:

您通常不能只将 H2 附加到 H1 上,因为正如 cmets 中指出的那样,这样做会产生无效堆。这种情况并不少见。

例如,想象两个最大堆:

h1 = [100]
h2 = [6,3,5,1,2,4]

    h1        h2

   100        6
            3   5
           1 2 4

如果你只是将 h2 附加到 h1,你会得到:

    100
  6    3
 5 1  2 4

这显然是无效的,因为 4 是 3 的孩子。

如果 h1=[100,98],同样的事情也会发生:

       100
    99     6
   3  5  1   2
 4

您要做的是将 h2 附加到 h1,然后运行一个缩写的 build-heap,重新排列 h2 中的项目以反映它们在堆中的新位置。您已经知道从 h2 添加的所有项目都小于 h1 中的最小项目,因此您不必触摸 h1 中的任何项目。

这个和标准build-heap的唯一区别是开始和结束位置。基本上,您从 h2 的中间开始,然后向后工作到 h2 的开头。

h1_length = h1.length
h2_length = h2.length
h1.array.append(h2.array)  // copies items from h2 to h1
// rearrange h2 items
start = h1_length + (h2_length/2)
for (item = start; item > h1_length; --item)
{
    i = item
    // This assumes that the root of the heap is at 0.
    // If the root is at 1, then the left child is at i*2
    while (i*2+1 < h1.length)
    {
        // get the largest child of this item
        leftChildIndex = i*2+1
        rightChildIndex = leftChildIndex + 1
        largestChildIndex = leftChildIndex
        if (rightChildIndex < h1.length &&
            h1.array[rightChildIndex] > h1.array[leftChildIndex)
        {
            largestChildIndex = rightChildIndex
        }
        // if the item is greater than or equal to its largest child,
        // then the item is where it belongs.
        if (h1.array[i] >= h1.array[largestChildIndex])
        {
            break;
        }
        // swap the item with its child, and check again
        swap(h1.array[i], h1.array[largestChildIndex])
        i = largestChildIndex
    }
}

build-heap 算法被证明是 O(n),其中 n 是您正在构建的堆中的项目数。由于您只使用 h2.length 项目,这将花费 O(h2.length) 时间。

【讨论】:

  • 我从你的代码中看到,它的复杂度是 O(nlgn),假设 n=h2 / 2。我错过了什么吗?
  • @seleciii44:正如我在上一段中指出的,build-heap 算法是 O(n)。有关说明,请参阅 stackoverflow.com/questions/9755721/…
  • 谢谢,我明白了。
猜你喜欢
  • 2015-10-06
  • 2013-09-25
  • 2021-10-22
  • 2019-04-11
  • 2018-09-29
  • 2014-07-21
  • 2012-05-18
  • 1970-01-01
  • 2021-07-27
相关资源
最近更新 更多