从Python heapq中检索最小值

时间:2014-11-04 19:21:16

标签: python heap

来自Python docs

  

后两个函数[heapq.nlargest和heapq.nsmallest]对较小的n值表现最佳。对于   值越大,使用sorted()函数效率越高。   此外,当n == 1时,使用内置的min()和更高效   max()函数。

如果我想检索最小堆中的最小元素,为什么Python文档建议使用min(),我假设在O(n)时间内运行, 我可以在O(1)时间内检索堆中的第一个元素吗? (我假设堆中的第一个元素是最小的)

2 个答案:

答案 0 :(得分:2)

nsmallest提供的nlargestheapq方法并不假设传递给它们的参数已经是堆格式。相反,他们试图在论证遍历时“堆积”论证,这比对小k值的前k元素进行彻底排序更有效,但是对于k恰好等于1,它甚至更快地避免支付随你堆积开销,只需直接使用min

你的陈述是正确的。如果给你一个你可以保证已经堆积的数组,并且之后没有改变,那么访问第一个元素会给你min(分别是max-heap的最大值)。

source code for heapq(也许我正在看旧代码?)对我来说似乎仍然很奇怪。 nsmallestn ==1这样的特殊情况(第397行):

def nsmallest(n, iterable, key=None):
    """Find the n smallest elements in a dataset.

    Equivalent to:  sorted(iterable, key=key)[:n]
    """
    # Short-cut for n==1 is to use min() when len(iterable)>0
    if n == 1:
        it = iter(iterable)
        head = list(islice(it, 1))
        if not head:
            return []
        if key is None:
            return [min(chain(head, it))]
        return [min(chain(head, it), key=key)] 

    # ... rest of function

只是在解释器中使用该表达式使它看起来很奇怪:

In [203]: foo = list(itertools.islice([1,2,3], 1)); it = iter([1,2,3]); x = itertools.chain(foo, it);

In [204]: x.next()
Out[204]: 1

In [205]: x.next()
Out[205]: 1

In [206]: x.next()
Out[206]: 2

In [207]: x.next()
Out[207]: 3

In [208]: x.next()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-208-e05f366da090> in <module>()
----> 1 x.next()

StopIteration:

它似乎正在构建一个生成器(它立即变为list)只接受第一个元素(正如你可能期望的最小堆),但奇怪的是chain s它有一个普通的旧发电机,它将遍及整个阵列。

我同意,如果您从list开始并想要查询最小元素,最好将其保留为list并使用min。但是,如果你被交给最小堆,是的,你应该只检查第一个元素 - 这是首先将它堆积起来的一部分。

但无论如何,这个源代码对于将最小堆传递给min看起来很奇怪 - 我非常欢迎更多关于它正在做什么的解释 - 并且可能指向一些更近期的C级代码heapq的实现,如果有的话。

答案 1 :(得分:0)

如果您只需要在堆化列表中选择一个最小元素,只需执行 list[0]:

import heapq
lst = [1,-1,100,200]
heapq.heapify(lst)

min_value = lst[0]

上面的文档是指获取 n 个最小的数字,如果 n 很大,堆不是最有效的数据结构。