如何在10亿个整数中找出前1000个最大的数(TopN算法)
生活随笔
收集整理的这篇文章主要介绍了
如何在10亿个整数中找出前1000个最大的数(TopN算法)
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
面试题目:如何在10亿个整数中找出前1000个最大的数。
我们知道排序算法有很多:
缺点:冒泡排序内层循环需要大量交换元素。复杂度介于O(n)和O(n^2)之间。
缺点:第一次排序复杂度是O(n),第二次排序复杂度是O(n/2),第三次排序复杂度是O(n/4)....
将比基准小的元素存储在txt1中,比基准大的文件存储在txt2中,然后通过类似方法二的形式,最后求出TopN。
缺点:磁盘读取,写入次数过多。
MapReduce:单机内存和性能确实受限,那么我们可以将10亿个分段存储在不同的机器上,每台机器计算各自的TopN,最后汇总。
缺点:空间换时间。
最优解:小顶堆
在内存中维护一个长度为N的数组,根据堆的性质,每一个节点都比他的左右子节点小,先取出前N个数并构建小顶堆,然后将所有数据与堆顶比较大小,如果比堆顶小就直接丢弃,如果比堆顶大则替换堆顶,并且重新构建这个堆。
构建小顶堆的过程:先要找到最后一个非叶子节点,数组的长度为6,那么最后一个非叶子节点就是:长度/2-1,也就是6/2-1=2,然后下一步就是比较该节点值和它的左右节点值,如果该节点大于其左\右子树的值就交换(意思就是将最小的值放到该节点)。如果该节点不是叶子结点,则递归这一过程,直到这个节点变成叶子节点。
具体执行代码如下:
import java.util.Random;/*** @author vincent* @time 2019-08-07 11:59*/ public class TopN {public static int N = 10; //Top10public static int LEN = 100000000; //1亿个整数public static int arrs[] = new int[LEN];public static int result[] = new int[N]; //在内存维护一个长度为N的小顶堆public static int len = result.length;//堆中元素的有效元素 heapSize<=lenpublic static int heapSize = len;public static void main(String[] args) {//生成随机数组for(int i = 0;i<LEN;i++){arrs[i] = new Random().nextInt(999999999);}//构建初始堆for(int i = 0;i<N;i++){result[i] = arrs[i];}//构建小顶堆long start =System.currentTimeMillis();buildMinHeap();for(int i = N;i<LEN;i++){if(arrs[i] > result[0]){result[0] = arrs[i];minHeap(0);}}System.out.println(LEN+"个数,求Top"+N+",耗时"+(System.currentTimeMillis()-start)+"毫秒");print();}/*** 自底向上构建小堆*/public static void buildMinHeap(){int size = len / 2 -1 ; //最后一个非叶子节点for(int i = size;i>=0;i--){minHeap(i);}}/*** i节点为根及子树是一个小堆* @param i*/public static void minHeap(int i){int l = left(i);int r = right(i);int index = i;if(l<heapSize && result[l]< result[index]){index = l;}if(r<heapSize && result[r]< result[index]){index = r;}if(index != i){int t = result[index];result[index] = result[i];result[i] = t;//递归向下构建堆minHeap(index);}}/*** 返回i节点的左孩子* @param i* @return*/public static int left(int i){return 2*i;}/*** 返回i节点的右孩子* @param i* @return*/public static int right(int i){return 2*i+1;}/*** 打印*/public static void print(){for(int a: result){System.out.print(a+",");}System.out.println();} }
总结
以上是生活随笔为你收集整理的如何在10亿个整数中找出前1000个最大的数(TopN算法)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: mysql5.7中使用group by报
- 下一篇: Mesos介绍