如何从二进制堆中删除元素?

时间:2012-09-02 06:06:45

标签: algorithm data-structures language-agnostic

据我了解,binary heap不支持删除随机元素。如果我需要从binary heap移除随机元素

,该怎么办?

显然,我可以删除一个元素并在O(N)中重新排列整个堆。我可以做得更好吗?

3 个答案:

答案 0 :(得分:22)

是和否。

问题是二进制堆不支持任意元素的搜索。找到它本身就是O(n)

但是,如果你有一个指向元素的指针(而不仅仅是它的值) - 你可以用最右边的叶子交换元素,删除这个叶子,然后再重新堆积相关的子-heap(通过按需筛选新放置的元素)。这会导致O(logn)删除,但需要指向您要查找的实际元素的指针。

答案 1 :(得分:8)

阿米特的答案是正确的,但这里还有一个细微差别:

删除项目的位置(放置最右边的叶子的位置)可能需要冒泡(与父项比较并向上移动直到父项大于你)。 有时需要泡下来(与孩子比较并向下移动,直到所有孩子都比你小)。这一切都取决于具体情况。

答案 2 :(得分:3)

取决于“随机元素”的含义。如果它意味着堆包含元素[e1,e2,...,eN]并且想要删除一些ei(1< = i< = N),那么这是可能的。

如果您正在使用某个库中的二进制堆实现,则可能是它没有为您提供所需的API。在这种情况下,您应该寻找另一个拥有它的库。

如果您自己实施,则需要另外两个电话:

  1. 删除索引i处的节点的过程deleteAtIndex(heap,i) 通过将堆数组中的最后一个元素定位在i,减少 元素计数,最后向下/向上移动 新的第i个元素来保持堆不变量。最多 这个过程的常见用法是通过调用“弹出”堆 deleteAtIndex(heap,1) - 假设1-origin索引。这个操作 将运行O(log n)(但是,要完成,我会注意到最高限度可以 根据对元素键的一些假设,改进了O(log(log n))。

  2. 删除元素e(您的任意元素)的过程deleteElement(heap,e)。 您的堆算法将维护一个数组ElementIndex,以便ElementIndex [e]返回 元素e的当前索引:调用deleteAtIndex(heap,ElementIndex [e]) 然后会做你想要的。它也将在O(log n)中运行,因为数组访问是常量。

  3. 由于二进制堆通常用于仅弹出最高(或最低)的算法 优先级元素(而不是删除任意元素),我想有些库可能会错过deleteAtIndex API来节省空间(上面提到的额外的ElementIndex数组)。