通过键在 PriorityQueue 中查找元素

Posted

技术标签:

【中文标题】通过键在 PriorityQueue 中查找元素【英文标题】:Find an element in a PriorityQueue by key 【发布时间】:2018-06-14 14:50:27 【问题描述】:

假设我得到了一些钥匙。我想找到的是优先级队列中的一个元素,它的键等于或大于给定的键。

显然,我希望它在O(logn) 中完成。我几乎可以肯定 Java 提供了这种方法但找不到它(查看官方文档)

【问题讨论】:

【参考方案1】:

没有这样的方法。

优先级队列的底层实现是最小堆(也可以配置为最小堆)。因此对于具有最大堆属性的优先级队列,当您检查 peek 元素(即O(1) 操作)时,它将返回最大元素。在轮询它之后,将执行 heapify-ing 并且下一个顶部元素将是第二个最大值。这种复杂的O(logn) 复杂化。因此,如果您想获得大于或等于给定键的所有键,则需要不断从最大堆优先级队列轮询,直到顶部元素小于给定键。在最坏的情况下,这可能是O(nlogn)

同样在这些操作之后,队列结构将被改变,因为一些键已经被轮询。所以在下一个操作之前,你必须通过重新推送被轮询的键来恢复队列的状态,这也将是O(nlogn)

PriorityQueue<Integer> queue = new PriorityQueue<>(10, Collections.reverseOrder())

List<Integer> keysGreaterOrEqualTo(Integer key) 
    List<Integer> keys = new ArrayList<>();
    while(!queue.isEmpty() && queue.peek() >= key) 
        keys.add(queue.poll());
    
    return keys;

【讨论】:

【参考方案2】:

Java Priority Queue 有contains() 方法,如果在Priority Queue 中找到键,则返回true。 参考 - Reference

要查找大于或等于的键,您可以实现自己的自定义方法。如:

int searchkey = 5, foundKey = 0;

While(!pq.isEmpty())
  foundKey = pq.poll();   
  if(foundKey == searchKey || foundKey > searchKey)
    break;

System.out.println(foundKey == searchKey || foundKey > searchKey ? foundKey : -1);

【讨论】:

【参考方案3】:

有一种非破坏性的方法可以做到这一点。您可以使用iterator 进行搜索,而不是在找到符合条件的内容之前从队列中删除。

了解迭代器不会以任何特定顺序返回项目,因此如果您想要大于或等于某个值的最小项目,您仍然必须遍历整个集合。

这个复杂度显然是O(n)。接受的答案中描述的破坏性技术的复杂性是 O(k log n),其中k 是小于您正在搜索的项目的数量。最坏的情况是k=n,算法是O(n log n)。

【讨论】:

【参考方案4】:

我认为使用 TreeSet 可能会更好,特别是它的 tailSet 方法。它可以像优先队列一样使用,也是N log N。

【讨论】:

以上是关于通过键在 PriorityQueue 中查找元素的主要内容,如果未能解决你的问题,请参考以下文章

如果对象数组中两个不同对象的两个键在JavaScript中相同,则通过键查找对象[重复]

Redux - 通过其键在状态数组中查找对象并更新其另一个键

Java Collection - PriorityQueue 优先队列

PriorityQueue源码解析

java PriorityQueue(优先级队列)

priorityQueue 堆