python,heapq:heappushpop()和heappreplace()之间的区别

python,heapq:heappushpop()和heappreplace()之间的区别,python,heap,Python,Heap,在测试以下代码时,我无法找出函数heapq.heappushpop()和heapq.heappreplace()之间的区别(推/弹出操作的顺序除外) >>> from heapq import * >>> a=[2,7,4,0,8,12,14,13,10,3,4] >>> heapify(a) >>> heappush(a,9) >>> a [0, 2, 4, 7, 3, 9, 14, 13, 10, 8,

在测试以下代码时,我无法找出函数heapq.heappushpop()和heapq.heappreplace()之间的区别(推/弹出操作的顺序除外)

>>> from heapq import *
>>> a=[2,7,4,0,8,12,14,13,10,3,4]
>>> heapify(a)
>>> heappush(a,9)
>>> a
[0, 2, 4, 7, 3, 9, 14, 13, 10, 8, 4, 12]
>>> heappop(a)
0
>>> b=a.copy()
>>> heappushpop(a,6)
2
>>> heapreplace(b,6)
2
>>> a
[3, 4, 4, 7, 6, 9, 14, 13, 10, 8, 12]
>>> b
[3, 4, 4, 7, 6, 9, 14, 13, 10, 8, 12]

在许多常见的情况下,最终结果似乎是相同的,但过程和行为是不同的,并且在极端情况下可以看到:

heappushpop()
相当于先推,然后弹出,这意味着堆大小可能会在过程中发生变化(例如,如果堆为空,则会返回推送的元素)

heapreplace()
相当于先弹出,然后推动,还有一个额外的限制,即保证堆大小在过程中不会改变。这意味着您将在空堆上获得一个错误,以及其他有趣的角行为。

heapplace(a,x)
返回
a
中最初的最小值,而与
x
的值无关,而顾名思义,
heappushpop(a,x)
在弹出最小值之前,将
x
推到
a
。使用您的数据,以下是显示差异的序列:

>>> from heapq import *
>>> a = [2,7,4,0,8,12,14,13,10,3,4]
>>> heapify(a)
>>> b = a[:]
>>> heappushpop(a, -1)
-1
>>> heapreplace(b, -1)
0

非常重要的是要知道,拥有这些方法的原因是提高效率 就功能而言,您可以这样想

# if we assume len(list) == k
heapq.heappushpop(list, elem): # 2*log(K) runtime
  heapq.push(list, elem)  # log(K) runtime
  return heapq.pop(list)  # log(k) runtime

heapq.heapreplace(list, elem): # 2*log(K) runtime
  returnValue = heapq.pop(list) # log(K) runtime
  heapq.push(list, elem)        # log(K) runtime
  return returnValue 
但是,当您可以使用
push
pop
完成所有操作时,为什么还要有两个附加功能呢?
heapq.heappushpop()
heapq.heappreplace()
仅使用日志(K)时间

# if we assume len(list) == k
heapq.heappushpop(list, elem):         # log(K) runtime
  if elem < list[0]:
      return elem
  return heapq.heapreplace(list, elem) # log(K) runtime

heapq.heapreplace(list, elem):  # log(K) runtime
  returnValue = list[0]         # peek operation
  list[0] = elem
  heapq.bubbledown(list,0)      # restore heap structure in log(K) time
  return returnValue
#如果我们假设len(list)==k
heapq.heappushpop(列表,元素):#日志(K)运行时
如果元素<列表[0]:
返回元素
返回heapq.heappreplace(list,elem)#log(K)运行时
heapq.heappreplace(列表,元素):#日志(K)运行时
returnValue=列表[0]#查看操作
列表[0]=元素
heapq.bubbledown(列表,0)#在日志(K)时间内恢复堆结构
返回值
耗时的操作是
heapq.bubbledown
(实际上不是python api),在后台,此函数与


您会注意到,这些函数在解决以下问题时非常方便。如果只使用
pop
+
push
(就像在java中一样),速度会慢两倍:(

heapq.heappushpop
相当于先推,然后pop

heapq.heappreplace
相当于先弹出然后按下

作为演示:

>>> seq
[0, 1, 5, 2, 6, 7, 9, 3]
>>> heapq.heappushpop(seq, -1)
-1
>>> seq
[0, 1, 5, 2, 6, 7, 9, 3]
>>> heapq.heapreplace(seq, -1)
0
>>> seq
[-1, 1, 5, 2, 6, 7, 9, 3]

你能解释一下为什么heapq.bubbledown只是log(K)时间吗?@spspspli因为bubble down最多需要走h步,其中h是堆的高度。每走一步,它都会在树中下降一级。h是log(K)。只需添加到@Syscall comment中,此链接有助于新用户: