算法-topN問題

轉載自java實現Top n算法基礎,和Java高效讀取大文件

採用小頂堆或者大頂堆:

數據描述:求最大K個採用小頂堆,而求最小K個採用大頂堆。

實現步驟:根據數據前K個建立K個節點的小頂堆,在後面的N-K的數據的掃描中,

如果數據大於小頂堆的根節點,則根節點的值覆爲該數據,並調節節點至小頂堆。

如果數據小於或等於小頂堆的根節點,小根堆無變化。

求最小K個跟這求最大K個類似。時間複雜度O(nlogK)(n:數據的長度),特別適用於大數據的求Top K。

package com.java.algorithm.test;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;

/**
 * 求前面的最大K個 解決方案:小根堆
 * (數據量比較大(特別是大到內存不可以容納)時,偏向於採用堆)
 */
public class TopKByHeap {

    /**
     * 創建k個節點的小根堆
     *
     * @param a
     * @param k
     * @return
     */
    int[] createHeap(int a[], int k) {
        int[] result = new int[k];
        for (int i = 0; i < k; i++) {
            result[i] = a[i];
        }
        for (int i = 1; i < k; i++) {
            int child = i;
            int parent = (i - 1) / 2;
            int temp = a[i];
            while (parent >= 0 && child != 0 && result[parent] > temp) {
                result[child] = result[parent];
                child = parent;
                parent = (parent - 1) / 2;
            }
            result[child] = temp;
        }
        return result;

    }

    void insert(int a[], int value) {
        a[0] = value;
        int parent = 0;

        while (parent < a.length) {
            int lchild = 2 * parent + 1;
            int rchild = 2 * parent + 2;
            int minIndex = parent;
            if (lchild < a.length && a[parent] > a[lchild]) {
                minIndex = lchild;
            }
            if (rchild < a.length && a[minIndex] > a[rchild]) {
                minIndex = rchild;
            }
            if (minIndex == parent) {
                break;
            } else {
                int temp = a[parent];
                a[parent] = a[minIndex];
                a[minIndex] = temp;
                parent = minIndex;
            }
        }
    }

    /***
     * 從數組中加載數據並計算topN
     * @param input  源數據,用於計算topN的數組
     * @param k  topN中具體N的值
     * @return
     */
    int[] getTopKByHeap(int input[], int k) {
        int heap[] = this.createHeap(input, k);
        for (int i = k; i < input.length; i++) {
            if (input[i] > heap[0]) {
                this.insert(heap, input[i]);
            }
        }
        return heap;
    }

    /**從文件中加載數據並計算topN
     * 假設文件中一行數據格式爲:商品名稱/t 商品價格
     *
     * @param path 文件路徑
     */
    public int[] readDataFromBigFile(String path, int k) throws IOException {
        FileInputStream inputStream = null;
        Scanner sc = null;
        int[] result = new int[k];
        int index = 0;
        try {
            inputStream = new FileInputStream(path);
            sc = new Scanner(inputStream, "UTF-8");
            while (sc.hasNextLine()) {
                String line = sc.nextLine();
                String[] vals = line.split("\\s");
                int price = Integer.parseInt(vals[1]);
                if (index >= k) {
                    this.insert(result, price);
                } else {
                    result[index++] = price;
                    if (index == k) {
                        result = createHeap(result, k);
                    }
                }
            }
            // note that Scanner suppresses exceptions
            if (sc.ioException() != null) {
                throw sc.ioException();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (sc != null) {
                sc.close();
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int a[] = {4, 3, 5, 1, 2, 8, 9, 10};
        int result[] = new TopKByHeap().getTopKByHeap(a, 3);
        for (int temp : result) {
            System.out.println(temp);
        }
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章