简体   繁体   English

在Java中,如何查看()PriorityQueue中的前k个元素?

[英]in Java, How do I peek() the top k elements in a PriorityQueue ?

I see in the documentation, that PriorityQueue.peek() gives me access to the head of the queue in O(1), but what if I need access to the k top elements in the queue ? 我在文档中看到, PriorityQueue.peek()使我可以访问O(1)中的队列头,但是如果我需要访问队列中的k个top元素怎么办? I would use poll() k times, but that takes O(log(N)) , is there a way to do it in constant time ? 我会用poll() k次,但这需要O(log(N)),有没有办法在固定时间内做到呢?

Nope. 不。 If you could do it in constant time, you could do a comparison sort in linear time by heapifying an array and then finding the top N items, where N is all of them. 如果您可以在固定时间内执行此操作,则可以通过在数组中堆积数组然后找到前N个项(其中N个都是全部)来在线性时间内进行比较排序。

It's not possible to do it in constant time. 不可能在恒定时间内进行。 If your data is already in a PriorityQueue , removing the top k elements one by one is the best you can do. 如果您的数据已经在PriorityQueue ,则最好的方法是一个接一个地删除前k个元素。 Each remove costs you O(log(n)) but you have also figured that one out, hence the question. 每次删除都会花费O(log(n))但您也已经弄清楚了,因此是个问题。

However, if you are not forced to use a PriorityQueue , then you can do a partial sort on a list and retrieve the top k elements. 但是,如果不被迫使用PriorityQueue ,则可以对列表进行部分排序并检索前k个元素。 The asymptotic complexity of a partial sort is O(n*log(k)) . 部分排序的渐近复杂度为O(n*log(k)) It can be executed faster than the PriorityQueue approach if we also take into account the cost of setting up the priority queue, see Selecting top k items from a list efficiently in Java / Groovy (select the top 5 elements from a list of 10 million, PriorityQueue 300ms vs. partial sort 170ms). 如果我们还考虑设置优先级队列的成本,它的执行速度可以比PriorityQueue方法快,请参阅在Java / Groovy中从列表中高效选择前k个项目 (从1000万个列表中选择前5个元素, PriorityQueue 300毫秒与部分排序170毫秒)。

It can be done in O(klogk) time and O(k) additional space if the input is represented as an indexed sequence in heap order. 如果输入以堆顺序表示为索引序列,则可以在O(klogk)时间和O(k)附加空间中完成。 If k << n , that's a very good improvement. 如果k << n ,这是一个很好的改进。

static List <Integer> kLargest(List<Integer> xs, int k) {
 if (k <= 0) return Collections.emptyList();

 PriorityQueue<Map.Entry<Integer, Integer>> pq = 
    new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue));

 pq.add(new SimpleImmutableEntry<>(0, xs.get(0)));
 List<Integer> result = new ArrayList<>();
 for (int i = 0; i < k; i++) {
  Map.Entry <Integer, Integer> max = pq.remove();
  result.add(max.getValue());

  int j = max.getKey();
  int left = 2 * j + 1;
  int right = 2 * j + 2;

  if (left < xs.size()) pq.add(new SimpleImmutableEntry<>(left, xs.get(left)));
  if (right < xs.size()) pq.add(new SimpleImmutableEntry<>(right, xs.get(right)));
 }
 return result;
}

The question is, how to get the input in heap order. 问题是,如何按堆顺序获取输入。 If you create your own PriorityQueue class, you'll obviously have access to the internal array. 如果创建自己的PriorityQueue类,则显然可以访问内部数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM