如何在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报
- 下一篇: Springboot线程池的使用和扩展