[英]Can someone explain _siftup and _siftdown in this piece of code?
def remove(self, heap, element):
ind = heap.index(element)
heap[ind] = heap[-1]
del heap[-1]
if ind < len(heap):
heapq._siftup(heap, ind)
heapq._siftdown(heap, 0, ind)
我正在发送一个堆和一个需要删除的元素。 因此 ind 获取堆内该元素的ind
, heap[ind] = heap[-1]
将该元素放在顶部del heap[-1]
删除该元素。 但是下面的代码在做什么? 为什么 ind 会小于堆的长度? 我不知道这里发生了什么。
heap[ind] = heap[-1]
将该元素放在顶部
不,它实际上在复制该指数的最后一个元素ind
其中element
被发现,使element
实际上是删除(通过覆盖)。
为什么
ind
会小于堆的长度?
假设该element
实际出现在堆中,则ind
可以是 0 和len(heap)
之间的任何值。 因为通过执行delete heap[-1]
减小了堆的大小,考虑到删除后的长度, ind
甚至可能等于len(heap)
。
所以我们可以有两种可能; 任何一个:
ind == len(heap)
:当在堆的最后发现element
时会发生这种情况:边界情况。 通过delete heap[-1]
减少了堆的长度,因此我们有这种相等性。 在这种情况下没有什么可做的,因为delete heap[-1]
删除了必须删除的元素。
ind < len(heap)
:这是更通用的情况。 在这种情况下,我们没有删除element
,但其它元素。 该元素被复制到索引ind
,因此我们实际上删除了element
......通过覆盖它。 剩下要做的唯一一件事是恢复堆属性,这确保一个值不小于其父级且不大于其任一子级。
这就是我们需要调用 sift 函数的原因。 移动到索引ind
的值可能碰巧违反了堆属性。
但是下面的代码在做什么?
一些例子可能会阐明正在发生的事情
假设我们有这个(最小)堆:[1, 2, 3] 这是这棵树:
1
/ \
2 3
...我们调用这个函数来删除 1,然后是这样的:
我们确定 1 出现在索引 0 ( ind
)
值 3 被复制到索引 0,因此堆临时有一个重复条目:[3, 2, 3]
最后一个条目被删除,所以我们得到[3, 2],也就是这棵树:
3 / 2
由于这棵树违反了堆属性,我们调用heapq._siftdown
。 该方法会将值 3向下移动,直到它位于恢复堆属性的位置。 这将导致堆 [2, 3]:
2 / 3
假设我们有这个(最小)堆:[1, 5, 2, 6, 7, 3] 这是这棵树:
_1_
/ \
5 2
/ \ /
6 7 3
...我们调用这个函数来删除 6,然后会发生这样的事情:
我们确定 6 出现在索引 3 ( ind
)
值 3 被复制到索引 3,因此堆临时有一个重复条目:[1, 5, 2, 3, 7, 3]
最后一个条目被删除,所以我们得到 [1, 5, 2, 3, 7],也就是这棵树:
_1_ / \\ 5 2 / \\ 3 7
由于这棵树违反了堆属性,我们调用heapq._siftup
。 该方法会将值 3向上移动,直到它位于恢复堆属性的位置。 这将导致堆 [1, 3, 2, 5, 7]:
_1_ / \\ 3 2 / \\ 5 7
因此,在示例 1 中,我们看到需要进行筛选的情况,而在示例 2 中需要进行筛选。 这就是调用两个sift 方法的原因:这样可以确保移动的值将被带到它遵守堆属性的位置。 请注意,两个方法调用中的最多一个实际上会移动元素,而另一个调用是无害的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.