【转】Python里的堆heapq
实际上,Python没有独立的堆类型,而只有一个包含一些堆操作函数的模块。这个模块名为heapq(其中的q表示队列),默认为小顶堆。Python中没有大顶堆的实现。
常用的函数
| 函 数 | 描 述 |
|---|---|
| heappush(heap, x) | 将x压入堆中 |
| heappop(heap) | 从堆中弹出最小的元素(栈顶元素) |
| heapify([1,2,3]) | 让列表具备堆特征 |
| heapreplace(heap, x) | 弹出最小的元素(栈顶元素),并将x压入堆中 |
| nlargest(n, iter) | 返回iter中n个最大的元素 |
| nsmallest(n, iter) | 返回iter中n个最小的元素 |
heappop弹出最小的元素(总是位于索引0处\栈顶),并确保剩余元素中最小的那个位于索引0处(保持堆特征)。
heapreplace等于先heappop再heappush,但是比分别调用二者快。
堆操作的时间复杂度,下面是堆的实现方法:二叉堆、斐波那契堆、严格斐波那契堆……,常见模块里用的是斐波那契堆》

代码示例:
1 from heapq import * 2 3 class KthLargest: 4 5 def __init__(self, k: int, nums: List[int]): 6 self.k = k 7 self.q = [] 8 for x in nums: 9 self.add(x) 10 11 def add(self, val: int) -> int: 12 if len(self.q) < self.k: # 堆没满,加入堆 13 heappush(self.q, val) 14 elif val > self.q[0]: # val大于堆顶元素(第K大),踢掉堆顶元素,加入val 15 heapreplace(self.q, val) 16 return self.q[0] # 堆顶 17 import heapq 18 a = [2,4,1,5,6,3] 19 heapq.heapify(a) 20 print(a) # [1, 4, 2, 5, 6, 3] 21 import heapq 22 a = [2,4,1,5,6,3] 23 heapq.heapify(a) 24 b = heapq.heappop(a) 25 print(a) # [2, 4, 3, 5, 6] 26 print(b) # 1
用小顶堆实现大顶堆
heapq在实现的时候,没有给出一个类似Java的Compartor函数接口或比较函数,开发者给出了原因见这里:http://code.activestate.com/lists/python-list/162387/
于是,人们想出了一些很NB的思路,见:http://stackoverflow.com/questions/14189540/python-topn-max-heap-use-heapq-or-self-implement
我来概括一种最简单的:
将push(e)改为push(-e)、pop(e)改为-pop(e)。
也就是说,在存入堆、从堆中取出的时候,都用相反数,而其他逻辑与TopK完全相同,看代码:
1 class BtmkHeap(object): 2 def __init__(self, k): 3 self.k = k 4 self.data = [] 5 6 def Push(self, elem): 7 # Reverse elem to convert to max-heap 8 elem = -elem 9 # Using heap algorighem 10 if len(self.data) < self.k: 11 heapq.heappush(self.data, elem) 12 else: 13 topk_small = self.data[0] 14 if elem > topk_small: 15 heapq.heapreplace(self.data, elem) 16 17 def BtmK(self): 18 return sorted([-x for x in self.data])
经过测试,是完全没有问题的,这思路太Trick了……
转自:
记录每天生活的点点滴滴,呵呵呵呵呵呵

浙公网安备 33010602011771号