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

时间:2015-11-13 20:22:02

标签: python heap

当我测试出以下代码时,我无法弄清楚函数heapq.heappushpop()和heapq.heapreplace()之间的区别(推/弹操作的常规性)。

>>> 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]

4 个答案:

答案 0 :(得分:7)

无论heapreplace(a, x)的值如何,

a都会返回x中最初的最小值,而顾名思义,heappushpop(a, x)会将x推送到a在弹出最小值之前{1}} 。使用您的数据,这里有一个显示差异的序列:

>>> 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

答案 1 :(得分:5)

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

heappushpop()相当于首先推送,然后弹出,这意味着,除了其他事项之外,您的堆大小可能会在此过程中发生变化(例如,如果您的堆是空的,那么您将获得回到你推动的元素。)

heapreplace()相当于首先弹出,然后推送,并附加限制,保证您的堆大小不会在此过程中发生变化。这意味着你会在空堆上得到一个错误,以及其他有趣的角落行为。

答案 2 :(得分:2)

非常重要的是要知道heapq拥有这些方法的原因是提高效率
在功能方面,您可以这样思考

# 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 

但是,当您可以使用pushpop执行所有操作时,为什么还有两个附加功能? heapq.heappushpop()heapq.heapreplace() 仅使用log(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

耗时的操作是heapq.bubbledown(实际上不是python api),这个功能非常类似于heapq.pop()

在解决Merge K sorted arrays等问题时,您会注意到这些功能非常方便。如果你只使用pop + push(就像在java中一样),它会慢两倍:(

答案 3 :(得分:-1)

heapq.heappushpop 相当于先推送再弹出

同时

heapq.heapreplace 相当于先弹出再推送

作为演示:

>>> 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]