TopK问题

TopK问题是从海量数据中找出前K个数据。

比如从100万个整数中找出最大的100个整数,如果进行排序,时间复杂度是O(nlogn),代价高昂
TopK问题的解法是:用数据结构来解决,时间复杂度是O(nlogK)
堆在Java中的实现是优先级队列:PriorityQueue。(找最大数用小顶堆,找最小数用大顶堆)
TopK问题_第1张图片

接着上代码:

public class TestTopK {

    public static void main(String[] args) {
        int[] array = new int[]{98, 87, 567, 26, 343, 65, 678, 996, 31, 43};
        topK(array, 3);
    }

    /**
     * 在array这个数组中找出前k个最大的数
     */
    private static void topK(int[] array, int k) {
        PriorityQueue<Integer> queue = new PriorityQueue<>();   // 默认小顶堆
        // 前k个数无需做判断,直接放进堆里
        for (int i = 0; i < k; i++) {
            queue.offer(array[i]);
        }
        for (int i = k; i < array.length; i++) {
            if (array[i] > queue.peek()) {
                // 目标元素大于堆顶元素,丢出堆顶最小元素,放入目标元素
                queue.poll();
                queue.offer(array[i]);
            }
        }
        System.out.println(queue);
    }
}

运行结果:

[567, 678, 996]

和排序的性能对比:

先给出冒泡排序的代码:

    private static void bubbleSort(int[] array, int k) {
        for (int i = 1; i <= k; i++) {  //第i次排序
            for (int j = 0; j < array.length - i; j++) {
                if (array[j] > array[j + 1]) {
                    array[j] = array[j] ^ array[j + 1];
                    array[j + 1] = array[j] ^ array[j + 1];
                    array[j] = array[j] ^ array[j + 1];
                }
            }
        }
        // k次排序后,前k个最大的数到了后排,把它们找出来
        int[] lastK = Arrays.copyOfRange(array, array.length - k, array.length);
        System.out.println(Arrays.toString(lastK));
    }

再给出测试性能的主方法:

    public static void main(String[] args) {
        Random random = new Random(1);
        List<Integer> list = new ArrayList<>();
        StopWatch stopWatch = new StopWatch();
        // 100万个数字
        for (int i = 0; i < 1000000; i++) {
            int value = random.nextInt(100000000);
            list.add(value);
        }
        int[] array = list.stream().mapToInt(Integer::intValue).toArray();

        stopWatch.start("堆算法耗时");
        topK(array, 3);
        stopWatch.stop();

        stopWatch.start("排序算法耗时");
        bubbleSort(array, 3);
        stopWatch.stop();

        System.out.println(stopWatch.prettyPrint());
    }

运行结果:

[99999719, 99999873, 99999965]
[99999719, 99999873, 99999965]
StopWatch '': running time = 15933001 ns
---------------------------------------------
ns         %     Task name
---------------------------------------------
004018500  025%  堆算法耗时
011914501  075%  排序算法耗时

可以看到,性能相差了三倍,并且数据量越大,性能差距也越大。

你可能感兴趣的:(java,算法,开发语言)