top K问题的优化解法

top K问题的优化解法

​ 在大规模数据处理中,经常会遇到的一类问题:在海量数据中找出出现频率最好的前k个数,或者从海量数据中找出最大的前k个数,这类问题通常被称为top K问题。例如,在搜索引擎中,统计搜索最热门的10个查询词;在歌曲库中统计下载最高的前10首歌等。

100亿数据找出最大的1000个数字

对于海量数据处理,思路基本上是:必须分块处理,然后再合并起来。

1.局部淘汰法

​ 用一个容器保存前1000个数,然后将剩余的所有数字一一与容器内的最小数字相比,如果所有后续的元素都比容器内的1000个数还小,那么容器内这个1000个数就是最大1000个数。如果某一后续元素比容器内最小数字大,则删掉容器内最小元素,并将该元素插入容器,最后遍历完这1亿个数,得到的结果容器中保存的数即为最终结果了。此时的时间复杂度为O(n+m^2),其中m为容器的大小。

​ 这个容器可以用(小顶堆)最小堆来实现。我们知道完全二叉树有几个非常重要的特性,就是假如该二叉树中总共有N个节点,那么该二叉树的深度就是log2N,对于小顶堆来说移动根元素到底部或者移动底部元素到根部只需要log2N,相比N来说时间复杂度优化太多了(1亿的logN值是26-27的一个浮点数)。基本的思路就是先从文件中取出1000个元素构建一个小顶堆数组k,然后依次对剩下的100亿-1000个数字进行遍历m,如果m大于小顶堆的根元素,即k[0],那么用m取代k[0],对新的数组进行重新构建组成一个新的小顶堆。这个算法的时间复杂度是O((100亿-1000)log(1000)),即O((N-M)logM),空间复杂度是M

这个算法优点是性能尚可,空间复杂度低IO读取比较频繁,对系统压力大。

2.分治法

(1) 将100亿个数据分为1000个大分区,每个区1000万个数据

(2) 每个大分区再细分成100个小分区。总共就有1000*100=10万个分区

(3) 计算每个小分区上最大的1000个数

(4) 合并每个大分区细分出来的小分区。每个大分区有100个小分区,我们已经找出了每个小分区的前1000个数。将这100个分区的1000*100个数合并,找出每个大分区的前1000个数

(5) 合并大分区。我们有1000个大分区,上一步已找出每个大分区的前1000个数。我们将这1000*1000个数合并,找出前1000.这1000个数就是所有数据中最大的1000个数

3.Hash法

​ 如果这1亿个数据里面有很多重复的数,先通过Hash法,把这1亿个数字去重复,这样如果重复率很高的话,会减少很大的内存用量,从而缩小运算空间,然后通过分治法或最小堆法查找最大的1000个数。

请作者喝瓶肥宅快乐水