python的heapq模块提供了对堆的支持。这个模块实现的是小根堆。
import heapq
方法
heapify:将列表转换为堆
l = [1, 2, 3, 11, 12, 36, 1, 2]
heapq.heapify(l) #将列表转换为堆
print(l)
heappush/heappop: 插入/删除一个元素
- heappush:插入一个元素
- heappop:删除一个元素,因为堆的特征是heap[0]永远是最小的元素,所以一般都是删除第一个元素。
h = []
heapq.heappush(h, 2)
print(h)
l = [1, 2, 3, 11, 12, 36, 1, 2]
heapq.heapify(l) #将列表转换为堆
print(l)
heapq.heappop(l)
print(l)
heapreplace:删除最小元素值,添加新的元素值
import heapq
l = [1, 2, 3, 11, 12, 36, 2]
heapq.heapify(l)
print(l)
heapq.heapreplace(l, 99)
print(l)
nlargest/nsmallest:查询堆中的最大/小元素
- nlargest:查询堆中的最大元素,n表示查询元素个数
- nsmallest:查询堆中的最小元素,n表示查询元素的个数
import heapq
nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
print(heapq.nlargest(3, nums)) # Prints [42, 37, 23]
print(heapq.nsmallest(3, nums)) # Prints [-4, 1, 2]
import heapq
portfolio = [ {'name': 'IBM', 'shares': 100, 'price': 91.1},
{'name': 'AAPL', 'shares': 50, 'price': 543.22},
{'name': 'FB', 'shares': 200, 'price': 21.09},
{'name': 'HPQ', 'shares': 35, 'price': 31.75},
{'name': 'YHOO', 'shares': 45, 'price': 16.35},
{'name': 'ACME', 'shares': 75, 'price': 115.65} ]
cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
print(cheap)
print(expensive)
如果你想在一个集合中查找最小或最大的 N 个元素:
- 如果N 小于集合元素数量,函数 nlargest() 和 nsmallest() 是很合适的
- 如果 N 的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点(sorted(items)[:N] 或者是 sorted(items)[-N:])。
- 如果你仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用 min() 和max() 函数会更快些
应用
实现一个优先级队列
怎样实现一个按优先级排序的队列?并且在这个队列上面每次 pop 操作总是返回优先级最高的那个元素
import heapq
class PriorityQueue:
def __init__(self):
self._queue = []
self._index = 0
"""
参数:
item: 待压入的元素
priority: 指定优先级
如果两个有着相同优先级的元素,pop 操作按照它们被插入到队列的顺序返回的。
"""
def push(self, item, priority):
# (-priority, index, item)是一个元组。
# 优先级为负数的目的是使得元素按照优先级从高到低排序。
# 如果你使用元组 (priority, item) ,只要两个元素的优先级不同就能比较。但是如果两个元素优先级一样的话,那么比较操作出错
# 通过引入另外的 index 变量组成三元组 (priority, index, item)就可以避免出错,因为不可能有两个元素有相同的 index 值。
# Python 在做元组比较时候,如果前面的比较已经可以确定结果了,后面的比较操作就不会发生了
heapq.heappush(self._queue, (-priority, self._index, item))
self._index += 1
"""
返回值:
弹出一个元素之后,优先级最高的队列
"""
def pop(self):
return heapq.heappop(self._queue)[-1]
#**********************************
class Item:
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Item({!r})'.format(self.name)
q = PriorityQueue()
q.push(Item('foo'), 1)
q.push(Item('bar'), 5)
q.push(Item('spam'), 4)
q.push(Item('grok'), 1)
print(q.pop())
print(q.pop())
print(q.pop())
print(q.pop())
"""
Item('bar')
Item('spam')
Item('foo')
Item('grok')
"""