Python使用heapq實現小頂堆(TopK大)、大頂堆(BtmK小) | 四號程序員
Python使用heapq實現小頂堆(TopK大)、大頂堆(BtmK小)
需1求:給出N長的序列,求出TopK大的元素,使用小頂堆,heapq模塊實現。
04 |
class TopkHeap(object): |
05 |
def __init__(self, k): |
10 |
if len(self.data) < self.k: |
11 |
heapq.heappush(self.data, elem) |
13 |
topk_small = self.data[0] |
15 |
heapq.heapreplace(self.data, elem) |
18 |
return [x for x in reversed([heapq.heappop(self.data) for x in xrange(len(self.data))])] |
20 |
if __name__ == "__main__": |
22 |
list_rand = random.sample(xrange(1000000), 100) |
27 |
print sorted(list_rand, reverse=True)[0:3] |
上面的用heapq就能輕松搞定。
變態的需求來了:給出N長的序列,求出BtmK小的元素,即使用大頂堆。
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完全相同,看代碼:
01 |
class BtmkHeap(object): |
02 |
def __init__(self, k): |
10 |
if len(self.data) < self.k: |
11 |
heapq.heappush(self.data, elem) |
13 |
topk_small = self.data[0] |
15 |
heapq.heapreplace(self.data, elem) |
18 |
return sorted([-x for x in self.data]) |
經過測試,是完全沒有問題的,這思路太Trick了……