如何在 Scala 中获取优先级队列的第 k 个最小元素?
Posted
技术标签:
【中文标题】如何在 Scala 中获取优先级队列的第 k 个最小元素?【英文标题】:How do I get the k-th minimum element of a Priority Queue in Scala? 【发布时间】:2020-12-04 14:54:36 【问题描述】:我尝试了以下但似乎是错误的!
import collection.mutable
object Main
def main(args: Array[String]): Unit =
val asc = Ordering.by((_: (Double, Vector[Double]))._1).reverse
val pq = mutable.PriorityQueue.empty[(Double, Vector[Double])](asc)
pq.enqueue(12.4 -> Vector(22.0, 3.4))
pq.enqueue(1.2 -> Vector(2.3, 3.2))
pq.enqueue(9.1 -> Vector(12.0, 3.2))
pq.enqueue(32.4 -> Vector(22.0, 13.4))
pq.enqueue(13.2 -> Vector(32.3, 23.2))
pq.enqueue(93.1 -> Vector(12.0, 43.2))
val k = 3
val kthMinimum = pq.take(k).last
println(kthMinimum)
【问题讨论】:
您能补充一下代码打印的内容以及您希望打印的内容吗? 【参考方案1】:在Scala API doc中有明确说明:
只有 dequeue 和 dequeueAll 方法会返回元素 优先顺序(从堆中删除元素时)。标准 包括 drop、iterator 和 toString 在内的集合方法将删除 或以最方便的顺序遍历堆。
如果你想坚持使用PriorityQueue
,似乎dequeue
-ing k
次或pq.dequeueAll(k-1)
可能是实现优先检索的唯一手段。
【讨论】:
【参考方案2】:问题在于PriorityQueue
属性与继承的集合方法(如take
等)之间的不兼容。Scala 集合的另一个奇怪实现问题示例。
Java 的PriorityQueue
也存在同样的问题。
import java.util.PriorityQueue
val pQueue = new PriorityQueue[Integer]
pQueue.add(10)
pQueue.add(20)
pQueue.add(4)
pQueue.add(15)
pQueue.add(9)
val iter = pQueue.iterator()
iter.next() // 4
iter.next() // 9
iter.next() // 10
iter.next() // 20
iter.next() // 15
因此,PriorityQueue
在底层ArrayBuffer
中维护您的数据(不完全是,而是一个特殊的继承类)。这个“数组”保持堆积。继承的take
API 工作在这个堆积如山的类数组数据结构之上。最小堆数组的第一个 k
元素肯定与 minimum k
元素不同。
现在,定义 PriorityQueue
应该支持 enqueue
和 dequeue
。它只是维护最高优先级(第一个)元素,只是无法可靠地提供队列中的第 k 个元素。
虽然我说这是 Java 和 Scala 实现的问题,但它只是不可能为此想出一个理智的实现。我只是想知道为什么PriorityQueue
实现中仍然存在这些误导性方法。我们不能直接删除它们吗?
我强烈建议您使用适合您要求的最严格的 API。换句话说,坚持使用 Queue API 而不是使用继承的 API 方法(这可能会做一些奇怪的事情)。
虽然没有什么好的方法(因为它不是 PriorityQueue
明确要求的)。
您可以通过简单的dequeueing k times
在时间复杂度为k * log(n)
的循环中实现这一点。
val kThMinimum =
val pqc = pq.clone()
(1 until k).foreach(i => pqc.dequeue())
pqc.dequeue()
【讨论】:
以上是关于如何在 Scala 中获取优先级队列的第 k 个最小元素?的主要内容,如果未能解决你的问题,请参考以下文章
Leetcode刷题100天—215. 数组中的第K个最大元素(优先队列)—day15
Leetcode刷题100天—5855. 找出数组中的第 K 大整数(优先队列)—day22
Leetcode刷题100天—5855. 找出数组中的第 K 大整数(优先队列)—day22
Leetcode刷题100天—703. 数据流中的第 K 大元素(优先队列)—day16