Python 堆队列用于什么?

Python 堆队列用于什么?,python,Python,阅读Guido对这个问题臭名昭著的回答,我发现了这个模块 我还发现我不理解杰克的话,也不知道我能用它做些什么 你能向我解释一下(用6年前的目标)堆队列算法的用途和你能用它做什么吗 您能否提供一个简单的Python代码片段,在其中使用它(与heapq模块一起使用)可以解决一个问题,而使用它可以更好地解决这个问题,而不必使用其他东西?例如:您有一组1000个浮点数。您希望重复从集合中删除最小的项,并将其替换为0到1之间的随机数。最快的方法是使用heapq模块: heap = [0.0] * 1000

阅读Guido对这个问题臭名昭著的回答,我发现了这个模块

我还发现我不理解杰克的话,也不知道我能用它做些什么

你能向我解释一下(用6年前的目标)堆队列算法的用途和你能用它做什么吗


您能否提供一个简单的Python代码片段,在其中使用它(与
heapq
模块一起使用)可以解决一个问题,而使用它可以更好地解决这个问题,而不必使用其他东西?

例如:您有一组1000个浮点数。您希望重复从集合中删除最小的项,并将其替换为0到1之间的随机数。最快的方法是使用heapq模块:

heap = [0.0] * 1000
# heapify(heap)   # usually you need this, but not if the list is initially sorted
while True:
    x = heappop(heap)
    heappush(head, random.random())
这需要每次迭代的时间,该时间在堆的长度上是对数的(即,对于长度为1000的列表,大约7个单位)。其他解决方案需要一个线性时间(即大约1000个单位,慢140倍,并且随着长度的增加越来越慢):

或:

甚至:

lst = [0.0] * 1000
while True:
    x = lst.pop()   # get the largest one in this example
    bisect.insort(lst, random.random())   # linear

heapq
实现,这是一种部分排序的数据结构。特别是,它们有三个有趣的操作:

  • heapify
    在O(n)时间内就地将列表转换为堆
  • heappush
    在O(lgn)时间内向堆添加元素
  • heappop
    在O(lgn)时间内从堆中检索最小的元素
许多有趣的算法依赖于堆来获得性能。最简单的可能是部分排序:获取列表中k个最小(或最大)元素,而不对整个列表进行排序
heapq.nsmalest
nlargest
)会这样做。这可以解释为:

def nlargest(n, l):
    # make a heap of the first n elements
    heap = l[:n]
    heapify(heap)

    # loop over the other len(l)-n elements of l
    for i in xrange(n, len(l)):
        # push the current element onto the heap, so its size becomes n+1
        heappush(heap, l[i])
        # pop the smallest element off, so that the heap will contain
        # the largest n elements of l seen so far
        heappop(heap)

    return sorted(heap, reverse=True)

分析:设N为
l
中的元素数
heapify
运行一次,成本为O(n);那是微不足道的。然后,在一个运行N-N=O(N)次的循环中,我们分别以O(lgn)的代价执行
heapop
heappush
,给出了O(N lgn)的总运行时间。当N>>N时,与另一个明显的算法相比,这是一个巨大的胜利,
排序(l)[:N]
,它需要O(N lgn)时间。

谢谢。尽管如此,我不明白这比在collections.deque(maxlen=n)中保存值有什么好处,如果我们遇到一个大于最后一个的值,只需附加()它。仅仅检查新值是否大于deque中的最后一个值并不能给出正确的算法(假设n=2,deque包含
[3,5]
你会遇到
4
)。您必须以O(n)的代价对deque进行排序插入,从而产生O(n×n)的总运行时间。事实上,我错过了这一点。谢谢你这么精确。酷。我试过了,我发现我找不到更好的方法了。但是我不明白为什么访问heapqueue中的最小/最大值会那么快。是因为它们的内部结构是这样的吗?这是否意味着它的迭代/随机访问更慢?与其他解决方案相比,对内存消耗的影响是什么?@e-satis(以及任何算法教科书)介绍了二进制堆算法。堆根本不提供随机访问(尽管删除算法可以推广,保持O(lgn)保证)。内存使用量很小:与数组(Python的
列表
)完全相同。可以想象,wikipedia是我检查的第一个地方。但我不是一个数学爱好者,开发人员对开发人员的解释让我感觉好多了,“堆”只是一个Python列表,按某种巧妙的顺序排列。只要只在其上使用函数heappush()和heappop(),那么它就会保持这种巧妙的顺序,并且heappush()/heappop()可以在对数时间内工作。这基本上就是你需要知道的全部;您不需要深入了解这些函数是如何工作的,就可以了解如何使用它们。注意,我作弊了,在我的示例中没有使用heapify()(因为在这个特殊情况下不需要它);修正了。我和拉斯曼一样喜欢你的答案。很抱歉,我不能两者都接受。
lst = [0.0] * 1000
while True:
    x = lst.pop()   # get the largest one in this example
    bisect.insort(lst, random.random())   # linear
def nlargest(n, l):
    # make a heap of the first n elements
    heap = l[:n]
    heapify(heap)

    # loop over the other len(l)-n elements of l
    for i in xrange(n, len(l)):
        # push the current element onto the heap, so its size becomes n+1
        heappush(heap, l[i])
        # pop the smallest element off, so that the heap will contain
        # the largest n elements of l seen so far
        heappop(heap)

    return sorted(heap, reverse=True)