1. 程式人生 > >海量資料處理的 Top K演算法(問題) 小頂堆實現

海量資料處理的 Top K演算法(問題) 小頂堆實現

問題描述:有N(N>>10000)個整數,求出其中的前K個最大的數。(稱作Top k或者Top 10)

  問題分析:由於(1)輸入的大量資料;(2)只要前K個,對整個輸入資料的儲存和排序是相當的不可取的。

        可以利用資料結構的最小堆(小頂堆)來處理該問題。

        最小堆如圖所示,對於每個非葉子節點的數值,一定不大於孩子節點的數值。這樣可用含有K個節點的最小堆來儲存K個目前的最大值(當然根節點是其中的最小數值)。

      每次有資料輸入的時候可以先與根節點比較。若不大於根節點,則捨棄;否則用新數值替換根節點數值。並進行最小堆的調整。

在系統中,我們經常會遇到這樣的需求:將大量(比如幾十萬、甚至上百萬)的物件進行排序,然後只需要取出最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有類似的最小堆結構,但是當我們需要處理更復雜的問題時,可能依然需要自己定製。