您可以很容易地从堆中删除第i个元素:
h[i] = h[-1]
h.pop()
heapq.heapify(h)
只需用最后一个元素替换要删除的元素,并删除最后一个元素,然后重新堆叠堆。这是O(n),如果你希望你可以在O(log(n))中做同样的事情,但是你需要调用几个内部的heapify函数,或者更好的是,larsmans指出只需复制_siftup / _siftdown从heapq.py到你自己的代码:
h[i] = h[-1]
h.pop()
heapq._siftup(h, i)
heapq._siftdown(h, 0, i)
请注意,在每种情况下,您不能只是h [i] = h.pop(),因为如果我引用最后一个元素将失败。如果特殊情况下删除最后一个元素,那么可以组合覆盖和弹出。
请注意,根据堆的典型大小,您可能会发现只是调用heapify,而理论上效率较低的可能比重新使用_siftup / _siftdown更快:一点反思会显示heapify可能在C中实现,但C实现的内部功能不暴露。如果性能重要,那么您可以考虑对典型数据进行一些时序测试,以查看哪个是最佳的。除非你真的很大,否则大O可能不是最重要的因素。
编辑:有人尝试编辑此答案,以删除对_siftdown的调用,并附有以下注释:
_siftdown is not needed. New h[i] is guaranteed to be the smallest of the old h[i]’s children, which is still larger than old h[i]’s parent
(new h[i]’s parent). _siftdown will be a no-op. I have to edit since I
don’t have enough rep to add a comment yet.
在这个评论中他们错过的是,h [-1]可能不是h [i]的孩子。在h [i]插入的新值可能来自堆的完全不同的分支,因此可能需要在任一方向筛选。
另外给注释问为什么不只是使用sort()来恢复堆:调用_siftup和_siftdown都是O(log n)操作,调用heapify是O(n)。调用sort()是一个O(n log n)操作。调用排序很有可能是足够快的,但是对于大的堆,这是一个不必要的开销。