top-K 算法总结

问题描述:有 N (N>1000000)个数,求出其中的前K个最小的数(又被称作topK问题)

1 最基本思路

将N个数进行完全排序,从中选出排在前K的元素即为所求。有了这个思路,我们可以选择相应的排序算法进行处理,目前来看快速排序,堆排序和归并排序都能达到**O(NlogN)**的时间复杂度。

2 优先队列

可以采用数据池的思想,选择其中前K个数作为数据池,后面的N-K个数与这K个数进行比较,若小于其中的任何一个数,则进行替换。这种思路的算法复杂度是O(N*K).
剩余的N-K个数与前面K个数比较的时候,是顺序比较的,算法复杂度是K。

3 大根堆

大根堆维护一个大小为K的数组,目前该大根堆中的元素是排名前K的数,其中根是最大的数。此后,每次从原数组中取一个元素与根进行比较,如小于根的元素,则将根元素替换并进行堆调整(下沉),即保证大根堆中的元素仍然是排名前K的数,且根元素仍然最大;否则不予处理,取下一个数组元素继续该过程。该算法的时间复杂度是O(N*logK),一般来说企业中都采用该策略处理topK问题,因为该算法不需要一次将原数组中的内容全部加载到内存中,而这正是海量数据处理必然会面临的一个关卡。

4 快速排序

利用快速排序的分划函数找到分划位置K,则其前面的内容即为所求。该算法是一种非常有效的处理方式,时间复杂度是O(N)(证明可以参考算法导论书籍)。对于能一次加载到内存中的数组,该策略非常优秀。

代码实现:基于快排和堆排的TopK算法

原文链接:https://www.jianshu.com/p/5b8f00d6a9d7

5 “冒泡排序”获取TopK

(1)可以避免对所有数据进行排序,只排序部分;
(2)冒泡排序是每一轮排序都会获得一个最大值,则K轮排序即可获得TopK。

6 局部淘汰法 – 借助数据结构"堆"获取TopK

(1)堆:分为大顶堆(堆顶元素大于其他所有元素)和小顶堆(堆顶其他元素小于所有其他元素)。
(2)我们使用小顶堆来实现。
(3)取出K个元素放在另外的数组中,对这K个元素进行建堆。
(4)然后循环从K下标位置遍历数据,只要元素大于堆顶,我们就将堆顶赋值为该元素,然后重新调整为小顶堆。
(5)循环完毕后,K个元素的堆数组就是我们所需要的TopK。

7 分治法 – 借助”快速排序“获取TopK

(1)比如有10亿的数据,找处Top1000,我们先将10亿的数据分成1000份,每份100万条数据。
(2)在每一份中找出对应的Top 1000,整合到一个数组中,得到100万条数据,这样过滤掉了999%%的数据。
(3)使用快速排序对这100万条数据进行”一轮“排序,一轮排序之后指针的位置指向的数字假设为S,会将数组分为两部分,一部分大于S记作Si,一部分小于S记作Sj。
(4)如果Si元素个数大于1000,我们对Si数组再进行一轮排序,再次将Si分成了Si和Sj。如果Si的元素小于1000,则我们需要在Sj中获取1000-count(Si)个元素的,也就是对Sj进行排序
(5)如此递归下去即可获得Top-K。

原文链接:http://www.mianshigee.com/question/12518zap

你可能感兴趣的:(数据挖掘,算法,java,数据结构,快速排序,大数据)