算法:用Java實現在海量的數據中,找到最大的N個數字,也就是TopN問題

我準備用優先隊列來實現TopN問題,海量數據是指計算機內存裝不下的很大的數據文件,在裏面找到最大的N個數字。因爲是海量的數據文件,所以還是按照以前外部排序那種,每次讀文件的一部分,然後一個一個地吐數字,以確保內存可以處理。然後在讀文件吐出的一個個數字中,找到最大的N個數字

實現思路:

  1. 將海量的數據用文件流讀入,可以一行一行地讀,然後數字一個一個地吐出來
  2. 先吐出N個數字,建立優先隊列,最小的數字優先級最大,可以用Java實現好了的優先隊列
  3. 繼續吐數字,如果吐出的數字小於等於優先隊列的最小值,則放過
  4. 如果吐出的數字大於優先隊列的最小值,則將優先隊列最小的數字(優先級最大)出隊,然後入隊剛剛吐出來的數字。注意,優先隊列裏面數字的個數永遠保持N個
  5. 所有的數字都吐完後,優先隊列裏面的N個數字就是海量數據中最大的N個數字

下面是我的實現代碼,比如我們想要在10000個數字裏面找到最大的20個數字,數字都是百萬級的:

import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Random;

/**
 * @author LiYang
 * @ClassName TopN
 * @Description 用優先隊列實現TopN問題
 * @date 2019/11/13 11:05
 */
public class TopN {
    
    //需要得到的最大數字的數量
    //就是TopN中的N
    private int topNum;
    
    //用於實現TopN的優先隊列
    private PriorityQueue<Long> priorityQueue;

    /**
     * TopN工具類的構造方法
     * @param topNum 需要統計的最大數字的個數
     */
    public TopN(int topNum) {
        this.topNum = topNum;
        this.priorityQueue = new PriorityQueue<>();
    }

    /**
     * 計算TopN的N個最大數字
     * @param element 海量數字之一
     */
    public void countTopN(long element) {
        //如果優先隊列裏面的數字已經有N個了
        if (priorityQueue.size() == topNum) {
            
            //查看優先隊列中最小數字
            long minimum = priorityQueue.peek();
            
            //如果當前數字比優先隊列中最小數字要大
            if (element > minimum) {
                
                //把優先隊列中最小數字出隊
                priorityQueue.poll();
                
                //讓更大的數字入隊
                priorityQueue.add(element);
            }
            
        //如果優先隊列裏面的數字還未到N個
        } else {
            //當前數字入隊優先隊列,並不做出隊操作
            priorityQueue.add(element);
        }
    }

    /**
     * 在文件讀完,countTopN操作結束後
     * 獲取最大N個數字的數組,升序排列
     * @return TopN數字數組,升序
     */
    public long[] getTopN() {
        //TopN的結果數組
        long[] result = new long[topNum];

        //將TopN的數字全部出隊
        for (int i = 0; i < result.length; i++) {
            //這樣操作,結果數組就是升序的
            result[i] = priorityQueue.poll();
        }
        
        //返回TopN的結果數組
        return result;
    }

    /**
     * 測試TopN工具類
     * 測試用例是百萬級的10000個數字,找出Top20的數字
     * @param args
     */
    public static void main(String[] args) {
        //模擬大文件上的海量數據
        long[] bigData = new long[10000];

        //隨機數類
        Random random = new Random();
        
        //生成百萬級的"大文件"上的數據
        for (int i = 0; i < bigData.length; i++) {
            bigData[i] = random.nextInt(10000000);
        }
        
        //創建TopN工具類的實例,統計最大的20個數字
        TopN topN = new TopN(20);

        //將"大文件"上的數據依次"吐出",進行統計
        for (int i = 0; i < bigData.length; i++) {
            topN.countTopN(bigData[i]);
        }
        
        //統計完畢,獲取Top20的最大的20個數字
        long[] result = topN.getTopN();

        //打印統計結果(最大的20個數字的數組)
        System.out.println("最大的20個數字:" + Arrays.toString(result));
    }
    
}

運行TopN工具類的main方法,控制檯輸出從10000個百萬級數字中獲得的最大的20個數字,測試通過(爲了方便查看,控制檯輸出內容適當做了換行操作):

最大的20個數字:
[9974849, 9977210, 9978159, 9978458, 9978577, 
9978882, 9982264, 9983253, 9983472, 9983855, 
9986296, 9987833, 9988433, 9989011, 9989025, 
9989105, 9989854, 9993490, 9997926, 9999579]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章