Part 1 数据结构及算法(二)
1.2 heapq模块
FUNCTIONS
heapify(...)
Transform list into a heap, in-place, in O(len(heap)) time.
heappop(...)
Pop the smallest item off the heap, maintaining the heap invariant.
heappush(...)
heappush(heap, item) -> None. Push item onto heap, maintaining the heap invariant.
heappushpop(...)
heappushpop(heap, item) -> value. Push item on the heap, then pop and return the smallest item
from the heap. The combined action runs more efficiently than
heappush() followed by a separate call to heappop().
heapreplace(...)
heapreplace(heap, item) -> value. Pop and return the current smallest value, and add the new item.
heapify(...)
Transform list into a heap, in-place, in O(len(heap)) time.
heappop(...)
Pop the smallest item off the heap, maintaining the heap invariant.
heappush(...)
heappush(heap, item) -> None. Push item onto heap, maintaining the heap invariant.
heappushpop(...)
heappushpop(heap, item) -> value. Push item on the heap, then pop and return the smallest item
from the heap. The combined action runs more efficiently than
heappush() followed by a separate call to heappop().
heapreplace(...)
heapreplace(heap, item) -> value. Pop and return the current smallest value, and add the new item.
1、查找最大或最小的N个元素
解决方案:heapq模块中的nlargest()和nsmallest()解决,内部利用堆排序实现,所以复杂度为O(log(N))
>>> nums=[1,2,3,4,5,6,7]
>>> heapq.nlargest(3,nums)
[7, 6, 5]
>>> heapq.nlargest(3,nums)
[7, 6, 5]
两个函数都会接受一个关键字参数,用于更复杂的参数
例如:按照protfolio中的price排序
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'])
总结:当要查找的元素个数相对比较小的时候,函数 nlargest() 和 nsmallest() 是很合适的。如果你仅仅想查找唯一的最小或最大 (N=1) 的元素的话,那么使用 min() 和max() 函数会更快些。类似的,如果 N 的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点 ( sorted(items)[:N] 或者是 sorted(items)[-
N:] )。需要在正确场合使用函数 nlargest() 和 nsmallest() 才能发挥它们的优势 (如果N 快接近集合大小了,那么使用排序操作会更好些)。
{'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'])
总结:当要查找的元素个数相对比较小的时候,函数 nlargest() 和 nsmallest() 是很合适的。如果你仅仅想查找唯一的最小或最大 (N=1) 的元素的话,那么使用 min() 和max() 函数会更快些。类似的,如果 N 的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点 ( sorted(items)[:N] 或者是 sorted(items)[-
N:] )。需要在正确场合使用函数 nlargest() 和 nsmallest() 才能发挥它们的优势 (如果N 快接近集合大小了,那么使用排序操作会更好些)。
2、优先级队列
import heapq class PriorityQueue: def __init__(self): self._queue = [] self._index = 0 def push(self, item, priority): # 元组比较,当第一个元素相同时才会比较后续的元素 heapq.heappush(self._queue, (-priority, self._index, item)) self._index += 1 def pop(self): return heapq.heappop(self._queue)[-1] # Example use 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("Should be bar:", q.pop()) print("Should be spam:", q.pop()) print("Should be foo:", q.pop()) print("Should be grok:", q.pop())第一个 pop() 操作返回优先级最高的元素。另外注意到如果两个有着相同优先级的元素 ( foo 和 grok ) , pop 操作按照它们被插入到队列的顺序返回的。