PYTHON:
def _siftdown(heap, startpos, pos):
newitem = heap[pos]
# Follow the path to the root, moving parents down until finding a place
# newitem fits.
while pos> startpos:
parentpos = (pos - 1)>> 1
parent = heap[parentpos]
if cmp_lt(newitem, parent):
heap[pos] = parent
pos = parentpos
continue
break
heap[pos] = newitem
我只是查看了heapq源代码,有人能解释第6行的内容吗?什么是>>运算符及其工作原理?
答案 0 :(得分:2)
>>
运算符表示bitwise right shift。向右移位(非负整数)相当于除以2并向下舍入。换句话说,spam >> 1
和spam // 2
是相同的。
那么,为什么要使用>>
?一些CPU - 尤其是较旧的CPU - 可以比分区更快地执行比特移位。大多数现代C编译器会在适当的时候将n / 2
优化为n >> 1
,但是较旧的编译器不会。当然,这在Python中几乎没有区别,但是大多数传统的堆实现 - 您将在数据结构教科书中看到的类型 - 将使用>>
。最重要的是,对于某些人(从这些教科书中学习的那种人),算法中的>>
是一个很好的信号,它是对数的。
所以这个
parentpos = (pos-1) >> 1
行试图返回其父级的索引。但为什么减去1?假设当前索引是4,这是树的第三级,然后你减去1得到3.并且二进制数是11,如果你向右移动那么它将是索引1,而不是父索引。
阅读the documentation的顶部:
此实现使用的数组
heap[k] <= heap[2*k+1]
和heap[k] <= heap[2*k+2]
适用于所有k
...
因此,对于k=1
,孩子是2*1+1 = 3
和2*1+2 = 4
。如下一段所述,这可能令人困惑:
以下API在两个方面与教科书堆算法不同:(a)我们使用从零开始的索引。这使得节点的索引与其子节点的索引之间的关系略显不明显,但更适合,因为Python使用从零开始的索引。
所以,您希望1
的孩子是2
和3
,但如果您以0为基础的术语来考虑它,那么您应该期待0
的孩子{1}}为1
和2
,1
的子女为3
和4
。
答案 1 :(得分:1)
>>
是右移运营商。它会丢弃最右边的位,这与除以2并忽略其余部分相同。所以该行可以写成parentpos = (pos - 1) // 2
。
Python的堆是从零开始的,因此节点 i 在2 * i + 1
和2 * i + 2
都有子项。它的父母位于(i - 1) // 2
。
siftdown 的作用是向上移动一个值(通过与父项交换),直到父级小于子级。