
scala.collection.mutable.PriorityQueue.scala Maven / Gradle / Ivy
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala
package collection
package mutable
import generic._
/** This class implements priority queues using a heap.
* To prioritize elements of type A there must be an implicit
* Ordering[A] available at creation.
*
* If multiple elements have the same priority in the ordering of this
* PriorityQueue, no guarantees are made regarding the order in which elements
* are returned by `dequeue` or `dequeueAll`. In particular, that means this
* class does not guarantee first in first out behaviour that may be
* incorrectly inferred from the Queue part of the name of this class.
*
* Only the `dequeue` and `dequeueAll` methods will return elements in priority
* order (while removing elements from the heap). Standard collection methods
* including `drop`, `iterator`, and `toString` will remove or traverse the heap
* in whichever order seems most convenient.
*
* Therefore, printing a `PriorityQueue` will not reveal the priority order of
* the elements, though the highest-priority element will be printed first. To
* print the elements in order, one must duplicate the `PriorityQueue` (by using
* `clone`, for instance) and then dequeue them:
*
* @example {{{
* val pq = collection.mutable.PriorityQueue(1, 2, 5, 3, 7)
* println(pq) // elements probably not in order
* println(pq.clone.dequeueAll) // prints Vector(7, 5, 3, 2, 1)
* }}}
*
* @tparam A type of the elements in this priority queue.
* @param ord implicit ordering used to compare the elements of type `A`.
*
* @author Matthias Zenger
* @since 1
*
* @define Coll PriorityQueue
* @define coll priority queue
* @define orderDependent
* @define orderDependentFold
* @define mayNotTerminateInf
* @define willNotTerminateInf
*/
@SerialVersionUID(736425014438295802L)
sealed class PriorityQueue[A](implicit val ord: Ordering[A])
extends AbstractIterable[A]
with Iterable[A]
with GenericOrderedTraversableTemplate[A, PriorityQueue]
with IterableLike[A, PriorityQueue[A]]
with Growable[A]
with Builder[A, PriorityQueue[A]]
with Serializable
with scala.Cloneable
{
import ord._
@SerialVersionUID(3491656538574147683L)
private class ResizableArrayAccess[A] extends AbstractSeq[A] with ResizableArray[A] with Serializable {
def p_size0 = size0
def p_size0_=(s: Int) = size0 = s
def p_array = array
def p_ensureSize(n: Int) = super.ensureSize(n)
def p_swap(a: Int, b: Int) = super.swap(a, b)
}
protected[this] override def newBuilder = PriorityQueue.newBuilder[A]
private val resarr = new ResizableArrayAccess[A]
resarr.p_size0 += 1 // we do not use array(0)
def length: Int = resarr.length - 1 // adjust length accordingly
override def size: Int = length
override def isEmpty: Boolean = resarr.p_size0 < 2
override def repr = this
def result = this
override def orderedCompanion = PriorityQueue
private def toA(x: AnyRef): A = x.asInstanceOf[A]
protected def fixUp(as: Array[AnyRef], m: Int): Unit = {
var k: Int = m
while (k > 1 && toA(as(k / 2)) < toA(as(k))) {
resarr.p_swap(k, k / 2)
k = k / 2
}
}
protected def fixDown(as: Array[AnyRef], m: Int, n: Int): Boolean = {
// returns true if any swaps were done (used in heapify)
var k: Int = m
while (n >= 2 * k) {
var j = 2 * k
if (j < n && toA(as(j)) < toA(as(j + 1)))
j += 1
if (toA(as(k)) >= toA(as(j)))
return k != m
else {
val h = as(k)
as(k) = as(j)
as(j) = h
k = j
}
}
k != m
}
/** Inserts a single element into the priority queue.
*
* @param elem the element to insert.
* @return this $coll.
*/
def +=(elem: A): this.type = {
resarr.p_ensureSize(resarr.p_size0 + 1)
resarr.p_array(resarr.p_size0) = elem.asInstanceOf[AnyRef]
fixUp(resarr.p_array, resarr.p_size0)
resarr.p_size0 += 1
this
}
override def ++=(xs: TraversableOnce[A]): this.type = {
val from = resarr.p_size0
for (x <- xs) unsafeAdd(x)
heapify(from)
this
}
private def unsafeAdd(elem: A): Unit = {
// like += but skips fixUp, which breaks the ordering invariant
// a series of unsafeAdds MUST be followed by heapify
resarr.p_ensureSize(resarr.p_size0 + 1)
resarr.p_array(resarr.p_size0) = elem.asInstanceOf[AnyRef]
resarr.p_size0 += 1
}
private def heapify(from: Int): Unit = {
// elements at indices 1..from-1 were already in heap order before any adds
// elements at indices from..n are newly added, their order must be fixed
val n = length
if (from <= 2) {
// no pre-existing order to maintain, do the textbook heapify algorithm
for (i <- n/2 to 1 by -1) fixDown(resarr.p_array, i, n)
}
else if (n - from < 4) {
// for very small adds, doing the simplest fix is faster
for (i <- from to n) fixUp(resarr.p_array, i)
}
else {
var min = from/2 // tracks the minimum element in the queue
val queue = scala.collection.mutable.Queue[Int](min)
// do fixDown on the parents of all the new elements
// except the parent of the first new element, which is in the queue
// (that parent is treated specially because it might be the root)
for (i <- n/2 until min by -1) {
if (fixDown(resarr.p_array, i, n)) {
// there was a swap, so also need to fixDown i's parent
val parent = i/2
if (parent < min) { // make sure same parent isn't added twice
min = parent
queue += parent
}
}
}
while (queue.nonEmpty) {
val i = queue.dequeue()
if (fixDown(resarr.p_array, i, n)) {
val parent = i/2
if (parent < min && parent > 0) {
// the "parent > 0" is to avoid adding the parent of the root
min = parent
queue += parent
}
}
}
}
}
/** Adds all elements provided by a `TraversableOnce` object
* into the priority queue.
*
* @param xs a traversable object.
* @return a new priority queue containing elements of both `xs` and `this`.
*/
def ++(xs: GenTraversableOnce[A]): PriorityQueue[A] = { this.clone() ++= xs.seq }
/** Adds all elements to the queue.
*
* @param elems the elements to add.
*/
def enqueue(elems: A*): Unit = { this ++= elems }
/** Returns the element with the highest priority in the queue,
* and removes this element from the queue.
*
* @throws java.util.NoSuchElementException
* @return the element with the highest priority.
*/
def dequeue(): A =
if (resarr.p_size0 > 1) {
resarr.p_size0 = resarr.p_size0 - 1
val result = resarr.p_array(1)
resarr.p_array(1) = resarr.p_array(resarr.p_size0)
resarr.p_array(resarr.p_size0) = null // erase reference from array
fixDown(resarr.p_array, 1, resarr.p_size0 - 1)
toA(result)
} else
throw new NoSuchElementException("no element to remove from heap")
def dequeueAll[A1 >: A, That](implicit bf: CanBuildFrom[_, A1, That]): That = {
val b = bf.apply()
while (nonEmpty) {
b += dequeue()
}
b.result()
}
/** Returns the element with the highest priority in the queue,
* or throws an error if there is no element contained in the queue.
*
* @return the element with the highest priority.
*/
override def head: A = if (resarr.p_size0 > 1) toA(resarr.p_array(1)) else throw new NoSuchElementException("queue is empty")
/** Removes all elements from the queue. After this operation is completed,
* the queue will be empty.
*/
def clear(): Unit = { resarr.p_size0 = 1 }
/** Returns an iterator which yields all the elements.
*
* Note: The order of elements returned is undefined.
* If you want to traverse the elements in priority queue
* order, use `clone().dequeueAll.iterator`.
*
* @return an iterator over all the elements.
*/
override def iterator: Iterator[A] = new AbstractIterator[A] {
private var i = 1
def hasNext: Boolean = i < resarr.p_size0
def next(): A = {
val n = resarr.p_array(i)
i += 1
toA(n)
}
}
/** Returns the reverse of this priority queue. The new priority queue has
* the same elements as the original, but the opposite ordering.
*
* For example, the element with the highest priority in `pq` has the lowest
* priority in `pq.reverse`, and vice versa.
*
* Ties are handled arbitrarily. Elements with equal priority may or
* may not be reversed with respect to each other.
*
* @return the reversed priority queue.
*/
def reverse = {
val revq = new PriorityQueue[A]()(ord.reverse)
// copy the existing data into the new array backwards
// this won't put it exactly into the correct order,
// but will require less fixing than copying it in
// the original order
val n = resarr.p_size0
revq.resarr.p_ensureSize(n)
revq.resarr.p_size0 = n
val from = resarr.p_array
val to = revq.resarr.p_array
for (i <- 1 until n) to(i) = from(n-i)
revq.heapify(1)
revq
}
/** Returns an iterator which yields all the elements in the reverse order
* than that returned by the method `iterator`.
*
* Note: The order of elements returned is undefined.
*
* @return an iterator over all elements sorted in descending order.
*/
def reverseIterator: Iterator[A] = new AbstractIterator[A] {
private var i = resarr.p_size0 - 1
def hasNext: Boolean = i >= 1
def next(): A = {
val n = resarr.p_array(i)
i -= 1
toA(n)
}
}
/** The hashCode method always yields an error, since it is not
* safe to use mutable queues as keys in hash tables.
*
* @return never.
*/
override def hashCode(): Int =
throw new UnsupportedOperationException("unsuitable as hash key")
/** Returns a regular queue containing the same elements.
*
* Note: the order of elements is undefined.
*/
def toQueue: Queue[A] = new Queue[A] ++= this.iterator
/** Returns a textual representation of a queue as a string.
*
* @return the string representation of this queue.
*/
override def toString() = toList.mkString("PriorityQueue(", ", ", ")")
/** Converts this $coll to a list.
*
* Note: the order of elements is undefined.
*
* @return a list containing all elements of this $coll.
*/
override def toList = this.iterator.toList
/** This method clones the priority queue.
*
* @return a priority queue with the same elements.
*/
override def clone(): PriorityQueue[A] = {
val pq = new PriorityQueue[A]
val n = resarr.p_size0
pq.resarr.p_ensureSize(n)
java.lang.System.arraycopy(resarr.p_array, 1, pq.resarr.p_array, 1, n-1)
pq.resarr.p_size0 = n
pq
}
}
object PriorityQueue extends OrderedTraversableFactory[PriorityQueue] {
def newBuilder[A](implicit ord: Ordering[A]): Builder[A, PriorityQueue[A]] = {
new Builder[A, PriorityQueue[A]] {
val pq = new PriorityQueue[A]
def +=(elem: A): this.type = { pq.unsafeAdd(elem); this }
def result(): PriorityQueue[A] = { pq.heapify(1); pq }
def clear(): Unit = pq.clear()
}
}
implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, PriorityQueue[A]] = new GenericCanBuildFrom[A]
}
/** This class servers as a proxy for priority queues. The
* elements of the queue have to be ordered in terms of the
* `Ordered[T]` class.
*
* @author Matthias Zenger
* @since 1
*/
@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0")
sealed abstract class PriorityQueueProxy[A](implicit ord: Ordering[A]) extends PriorityQueue[A] with Proxy {
def self: PriorityQueue[A]
/** Creates a new iterator over all elements contained in this
* object.
*
* @return the new iterator
*/
override def iterator: Iterator[A] = self.iterator
/** Returns the length of this priority queue.
*/
override def length: Int = self.length
/** Checks if the queue is empty.
*
* @return true, iff there is no element in the queue.
*/
override def isEmpty: Boolean = self.isEmpty
/** Inserts a single element into the priority queue.
*
* @param elem the element to insert
*/
override def +=(elem: A): this.type = { self += elem; this }
/** Adds all elements provided by an iterator into the priority queue.
*
* @param it an iterator
*/
override def ++=(it: TraversableOnce[A]): this.type = {
self ++= it
this
}
/** Adds all elements to the queue.
*
* @param elems the elements to add.
*/
override def enqueue(elems: A*): Unit = self ++= elems
/** Returns the element with the highest priority in the queue,
* and removes this element from the queue.
*
* @return the element with the highest priority.
*/
override def dequeue(): A = self.dequeue()
/** Returns the element with the highest priority in the queue,
* or throws an error if there is no element contained in the queue.
*
* @return the element with the highest priority.
*/
override def head: A = self.head
/** Removes all elements from the queue. After this operation is completed,
* the queue will be empty.
*/
override def clear(): Unit = self.clear()
/** Returns a regular queue containing the same elements.
*/
override def toQueue: Queue[A] = self.toQueue
/** This method clones the priority queue.
*
* @return a priority queue with the same elements.
*/
override def clone(): PriorityQueue[A] = new PriorityQueueProxy[A] {
def self = PriorityQueueProxy.this.self.clone()
}
}
/** This class implements synchronized priority queues using a binary heap.
* The elements of the queue have to be ordered in terms of the `Ordered[T]` class.
*
* @tparam A type of the elements contained in this synchronized priority queue
* @param ord implicit ordering used to compared elements of type `A`
*
* @author Matthias Zenger
* @since 1
* @define Coll `SynchronizedPriorityQueue`
* @define coll synchronized priority queue
*/
@deprecated("Comprehensive synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.ConcurrentSkipListSet as an alternative.", "2.11.0")
sealed class SynchronizedPriorityQueue[A](implicit ord: Ordering[A]) extends PriorityQueue[A] {
/** Checks if the queue is empty.
*
* @return true, iff there is no element in the queue.
*/
override def isEmpty: Boolean = synchronized { super.isEmpty }
/** Inserts a single element into the priority queue.
*
* @param elem the element to insert
*/
override def +=(elem: A): this.type = {
synchronized {
super.+=(elem)
}
this
}
/** Adds all elements of a traversable object into the priority queue.
*
* @param xs a traversable object
*/
override def ++=(xs: TraversableOnce[A]): this.type = {
synchronized {
super.++=(xs)
}
this
}
/** Adds all elements to the queue.
*
* @param elems the elements to add.
*/
override def enqueue(elems: A*): Unit = synchronized { super.++=(elems) }
/** Returns the element with the highest priority in the queue,
* and removes this element from the queue.
*
* @return the element with the highest priority.
*/
override def dequeue(): A = synchronized { super.dequeue() }
/** Returns the element with the highest priority in the queue,
* or throws an error if there is no element contained in the queue.
*
* @return the element with the highest priority.
*/
override def head: A = synchronized { super.head }
/** Removes all elements from the queue. After this operation is completed,
* the queue will be empty.
*/
override def clear(): Unit = synchronized { super.clear() }
/** Returns an iterator which yield all the elements of the priority
* queue in descending priority order.
*
* @return an iterator over all elements sorted in descending order.
*/
override def iterator: Iterator[A] = synchronized { super.iterator }
/** Checks if two queues are structurally identical.
*
* @return true, iff both queues contain the same sequence of elements.
*/
override def equals(that: Any): Boolean = synchronized { super.equals(that) }
/** Returns a textual representation of a queue as a string.
*
* @return the string representation of this queue.
*/
override def toString(): String = synchronized { super.toString() }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy