PriorityQueue实践和Topk问题

PriorityQueue的实践
PriorityQueue内部维护着一个堆,如果不传入比较器,则按自然排序,实际上维护着一个小顶堆。传入比较器后,把比较后小的值放在堆顶。

接下来我们看这样一个问题:如何得到一个数组最小的k个数。

解决该问题有两个思路:

  1. 利用Partition函数,得到数组中第n小的下标n,如果n=k-1,则前n个数则为最小的k个数;如果n<k-1,则对后面的数继续进行Partition排序;如果n>k-1,则对前面的数继续进行Partition排序,直到n=k-1;

  2. 建立一个容量为k的大堆顶,并从数组中逐个取数,如果堆的容量小于k,则向堆中添加该数;如果堆的容量等于k,则比较取的数和堆顶元素。堆顶元素始终是堆中元素的最大值,如果取出的数比堆顶元素小,则删除堆顶元素而把该数加入堆中。当遍历一次数组后,堆中的k个数即为数组中最小的k个数。

由于堆类似于一棵完全二叉树,因此每次的删除添加操作的时间复杂度都为logk,故整个算法的时间复杂度为O(nlogk)。该算法非常适用于处理海量数据(所有元素不必一次都读入内存中),当n很大,k很小的时候。

下面是代码实现:

private static ArrayList<Integer> theMinkOfArray(int[] array, int k) {
        ArrayList<Integer> result = new ArrayList<>();
        if (array == null || array.length <= 0) throw new RuntimeException("Invalid input");
        if (k == 0) return null;
        if (array.length < k) throw new RuntimeException("Invalid input");
        PriorityQueue<Integer> queue = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        for (int i=0; i < array.length; i++){
            if (queue.size()<k){
                queue.add(array[i]);
            }
            else {
                if (queue.peek() > array[i]){
                    queue.poll();
                    queue.add(array[i]);
                }
            }
        }
        for (int i=1; i<=k; i++){
            Integer min = queue.poll();
            result.add(min);
        }
        return result;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值