Python的heapify()不能很好地与列表理解和切片一起使用吗?

时间:2009-06-25 23:21:03

标签: python heap list-comprehension

我在一个程序中发现了一个有趣的错误,我有些懒惰地实现了,并且想知道我是否正确地理解它。简短版本是Python's heapq implementation实际上没有对列表进行排序,它只是以堆中心方式查看列表。具体来说,我希望heapify()能够生成一个有序的列表,以有序的方式促进列表理解。

使用优先级提示示例,如在Python文档中那样:

from heapq import heapify, heappush, heappop
from random import shuffle

class Item(object):
    def __init__(self, name):
        self.name = name

lst = []

# iterate over a pseudo-random list of unique numbers
for i in sample(range(100), 15):
    it = Item("Some name for %i" % i)
    heappush(lst, (i, it))

print([i[0] for i in lst])

结果

>>> [2, 22, 7, 69, 32, 40, 10, 97, 89, 33, 45, 51, 94, 27, 67]

我们注意到,这不是列表的原始排序,但显然是一些以堆为中心的排序为described here。我懒洋洋地期待这完全有序。

作为测试,通过heapify()运行列表不会导致更改(因为列表已经按堆排序):

heapify(lst)

print([i[0] for i in lst])

>>> [2, 22, 7, 69, 32, 40, 10, 97, 89, 33, 45, 51, 94, 27, 67]

而使用heappop()函数遍历列表会导致按预期排序:

lst2 = []
while lst: lst2.append(heappop(lst))

print([i[0] for i in lst2])

>>> [2, 7, 10, 22, 27, 32, 33, 40, 45, 51, 67, 69, 89, 94, 97]

因此,似乎heapq没有排序列表(至少在人类的意义上),而是heappush()heappop()函数能够理解堆排序列表。

结果:在分片列表上的任何切片和列表理解操作都会产生无序结果。

这是真的,这总是是真的吗?

(BTW:WinXP系统上的Python 3.0.1)

4 个答案:

答案 0 :(得分:8)

堆不是排序列表(它是部分排序的二叉树的表示)。

所以是的,你是对的,如果你期望一个堆化列表表现得像一个排序列表,你会感到失望。您可以对堆进行的唯一排序假设是heap[0]始终是其最小元素。

(很难为你已经写过的内容添加很多东西 - 你的问题是关于事物如何的优秀写作.8 - )

答案 1 :(得分:0)

  

结果:任何切片和列表   对...的理解操作   heapified list将产生非有序的   结果

     

这是真的,这总是如此吗?

如果您只想获得一次性排序列表,请使用:

myList.sort()

优先级队列/堆可用于实现排序,或者它们可用于以优先级形式保留队列。插入堆中的是O(lg n),get是O(1),删除是O(lg n),这比仅仅反复使用整个列表要好得多。

答案 2 :(得分:0)

“”“我期待heapify()产生一个有序的列表,以有序的方式促进列表理解。”“”:如果这个期望是基于手册的阅读,你应该提出一个docs bug报告

“”“结果:在堆化列表上的任何切片和列表理解操作都会产生无序结果。这是真的,这总是正确的吗?”“”:就像例如random.shuffle(),提到的活动未定义为生成“有序”结果。 可能偶尔产生“有序”结果,但这是巧合,不值得依赖,不值得问(恕我直言)。

答案 3 :(得分:0)

“结果:堆积列表上的任何切片和列表理解操作都会产生无序结果。这是真的,这总是正确的吗?”不,并非总是如此。虽然大部分时间都没有订购,但可以订购。 heapify()生成一个满足“堆不变量”的列表。在这种情况下,它是一个小堆。事实证明,排序列表也满足堆不变量(参见heapq第4段:“heap.sort()维护堆不变”)。所以从理论上讲,堆积列表也可能会被排序。