在系統中,我們經常會遇到這樣的需求:將大量(比如幾十萬、甚至上百萬)的對象進行排序,然后只需要取出最Top的前N名作為排行榜的數據,這即是一個TopN算法。常見的解決方案有三種:
(1)直接使用List的Sort方法進行處理。
(2)使用排序二叉樹進行排序,然后取出前N名。
(3)使用最大堆排序,然后取出前N名。
第一種方案的性能是最差的,后兩種方案性能會好一些,但是還是不能滿足我們的需求。最主要的原因在於使用二叉樹和最大堆排序時,都是對所有的對象進行排序,而不是將代價花費在我們需要的少數的TopN上。對於堆結構來說,並不需要你獲取所有的數據,只需要對前N個數據進行處理。因此可以通過堆棧的進入排出,用小頂堆實現,調整最小堆的時間復雜度為lnN,總時間復雜度為nlnN
myheap:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 最小堆化heap
def siftdown(heap, start, end):
while True:
left_child = start * 2 + 1
if left_child > end:
break
if left_child + 1 <= end:
if heap[left_child] > heap[left_child+1]:
left_child += 1
if heap[left_child] < heap[start]:
heap[left_child], heap[start] = heap[start], heap[left_child]
start = left_child
else:
break
def minheapstyle(heap):
first = len(heap) // 2 - 1
for x in xrange(first, -1, -1):
siftdown(heap, x, len(heap)-1)
def push(heap, item):
heap.append(item)
minheapstyle(heap)
def pushpop(heap, item):
if heap[0] < item:
heap[0] = item
minheapstyle(heap)
if __name__ == '__main__':
heap = [10,4,5,3,5,6,2]
minheapstyle(heap)
print heap
TOPN:
import myheap
def findminn(list, n):
heap = []
for x in list:
if len(heap) < n:
myheap.push(heap, x)
else :
myheap.pushpop(heap, x)
return heap
if __name__ == '__main__':
l = [5,6,7,8,9,10,5646]
#n=5
heap = findminn(l,5)
print heap
雖然python有類似的最小堆結構,但是當我們需要處理更復雜的問題時,可能依然需要自己定制。