问题:给出一堆大批量数据(比如10亿),如何从中快速查找出前N个最大值?
解决方案:采用最小堆的形式。先取出N个数据生成最小堆,然后再取出后面的值依次与堆顶比较,比堆顶小,则继续;比堆顶大,则交换值,并更新最小堆,直到所有值全部比较完,最后生成的最小堆就是最大的N个数据。
最小堆概念:最小堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值。如下图所示,即有节点2、节点3大于等于节点1;节点4、节点5大于等于节点2;节点6、节点7大于等于节点3。

最小堆的实例如下所示:

下面,我们通过Python代码来实现利用最小堆查找出数据的前N个最大值。
最小堆文件 MinHeap.py
class MinHeap():
def parent(self,n):
return (n-1)//2
def leftChild(self,n):
return 2*n+1
def rightChild(self,n):
return 2*n+2
#将list的前n个值构建为最小堆
def build_min_heap(self,n,list):
for i in range(n):
t=i;
while (t!=0 and (list[self.parent(t)] > list[t])):
temp = list[t]
list[t] = list[self.parent(t)]
list[self.parent(t)] = temp
t = self.parent(t)
#将数据与堆顶进行比较
def adjust_heap(self,i,n,list):
if(list[i]<list[0]):
return
#置换堆顶
temp = list[i];
list[i] = list[0];
list[0] = temp;
#调整最小堆
t=0
while(self.leftChild(t)<n and list[t]>list[self.leftChild(t)])or
(self.leftChild(t)<n and list[t]>list[self.leftChild(t)]):
if ((self.rightChild(t) < n )and (list[self.rightChild(t)] < list[self.leftChild(t)])):
#右孩子更小,置换右孩子
temp = list[t];
list[t] = list[self.rightChild(t)]
list[self.rightChild(t)] = temp
t = self.rightChild(t)
else:
#否则置换左孩子
temp = list[t]
list[t] = list[self.leftChild(t)]
list[self.leftChild(t)] = temp
t = self.leftChild(t)
def findTopN(self,n,list):
self.build_min_heap(n,list)
for i in range(len(list)):
self.adjust_heap(i,n,list)
def print(self,list):
print(list)
测试文件 test.py
from topN.MinHeap import MinHeap
if __name__ == "__main__":
minHeap = MinHeap()
#第一组测试
list = [56, 30, 71, 18, 29, 93, 44, 75, 20, 65, 68, 34]
print("原数组:")
minHeap.print(list)
minHeap.findTopN(5, list)
print("调整后数组:")
minHeap.print(list)
运行结果

方框中即是原数组中的前5个最大值。
参考:https://mp.weixin.qq.com/s/jES3gqaHfgJXbTgPmUbAqw