问题描述
选择问题或者说TopK问题是指给一堆无序的含有N个元素的数组,找出里面的最大的K个数(也可以是找出最小的K个数)。在本问题的基础上可以加上诸如元素数量较多,无法完整放入整个内存中,此时常规的先排序的思路是无效的。TopK问题的解决思路主要有如下几种,分别介绍如下。
常规排序思路
当不存在内存限制时,最先想到就是采用常规的排序算法了,目前基于比较的算法最好能够优化到O(nlgn)。如果要求稳定性则可以采用归并排序,否则可以使用堆排序或者快速排序,具体排序算法可见本人博客:各大排序算法的分析与实现
如果元素范围比较小还可以采用非比较的算法如计数排序,时间复杂度可以优化到O(N)。
部分排序思路
部分排序的思路是不对整个数组进行排序,只对K个元素进行排序,其基本思路如下:
1. 先读入K个元素并以非递增顺序排序
2. 读入新数据,如果新数据小于K个元素最小的数据,则直接丢弃,否则插入到正确的位置
3. 在结束后保存下来的K个元素的数组即为最大的K个数
在进行排序可以使用插入排序、堆排序思想。插入排序较为简单,以下实现采用堆排序的算法代码。采用堆排序的思路时间复杂度为建堆O(K)+更新堆O((N-K)logk),合计为O(NlogK)。
1 |
|
快速排序思路下的快速选择
快速排序会把比基准元素大的部分放到一边,其他放在另外一边,如果分割元素刚好处在分割K个最大元素的位置则可以直接返回结果。快速选择最好时间复杂度为O(N),最坏情况发生在每次分割元素取的最大或最小值,使得元素全部被分到一边,此时递推式为T(N)=T(N-1)+O(N)=O(N2)。
由于TopK问题特点,将比基准元素大的一方放到左边,当基准元素下标为K是则停止算法,实现代码如下。
1 |
|
算法测试
上述代码的测试程序如下:
1 |
|