海量数据处理的 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有类似的最小堆结构,但是当我们需要处理更复杂的问题时,可能依然需要自己定制。

猜你喜欢

转载自blog.csdn.net/hellojoy/article/details/81740121