@Beta @GwtCompatible public final class MinMaxPriorityQueue<E> extends java.util.AbstractQueue<E>
Usage example:
MinMaxPriorityQueue<User> users = MinMaxPriorityQueue.orderedBy(userComparator)
.maximumSize(1000)
.create();
As a Queue
it functions exactly as a PriorityQueue
: its
head element -- the implicit target of the methods peek()
, poll()
and AbstractQueue.remove()
-- is defined as the least element in
the queue according to the queue's comparator. But unlike a regular priority
queue, the methods peekLast()
, pollLast()
and
removeLast()
are also provided, to act on the greatest element
in the queue instead.
A min-max priority queue can be configured with a maximum size. If so, each time the size of the queue exceeds that value, the queue automatically removes its greatest element according to its comparator (which might be the element that was just added). This is different from conventional bounded queues, which either block or reject new elements when full.
This implementation is based on the
min-max heap
developed by Atkinson, et al. Unlike many other double-ended priority queues,
it stores elements in a single array, as compact as the traditional heap data
structure used in PriorityQueue
.
This class is not thread-safe, and does not accept null elements.
Performance notes:
PriorityQueue
with manual eviction above the maximum size. In many cases
Ordering.leastOf(java.lang.Iterable<E>, int)
may work for your use case with significantly
improved (and asymptotically superior) performance.
peek()
, peekFirst()
, peekLast()
, AbstractQueue.element()
, and size
are constant-time.
offer(E)
, add(E)
, and
all the forms of poll()
and AbstractQueue.remove()
) run in O(log n) time
.
AbstractCollection.remove(Object)
and AbstractCollection.contains(java.lang.Object)
operations require
linear (O(n)
) time.
PriorityQueue
, but
significantly slower.
Modifier and Type | Class and Description |
---|---|
static class |
MinMaxPriorityQueue.Builder<B>
The builder class used in creation of min-max priority queues.
|
private class |
MinMaxPriorityQueue.Heap
Each instance of MinMaxPriortyQueue encapsulates two instances of Heap:
a min-heap and a max-heap.
|
(package private) static class |
MinMaxPriorityQueue.MoveDesc<E> |
private class |
MinMaxPriorityQueue.QueueIterator
Iterates the elements of the queue in no particular order.
|
Modifier and Type | Field and Description |
---|---|
private static int |
DEFAULT_CAPACITY |
private static int |
EVEN_POWERS_OF_TWO |
private MinMaxPriorityQueue.Heap |
maxHeap |
(package private) int |
maximumSize |
private MinMaxPriorityQueue.Heap |
minHeap |
private int |
modCount |
private static int |
ODD_POWERS_OF_TWO |
private java.lang.Object[] |
queue |
private int |
size |
Modifier | Constructor and Description |
---|---|
private |
MinMaxPriorityQueue(MinMaxPriorityQueue.Builder<? super E> builder,
int queueSize) |
Modifier and Type | Method and Description |
---|---|
boolean |
add(E element)
Adds the given element to this queue.
|
boolean |
addAll(java.util.Collection<? extends E> newElements) |
private int |
calculateNewCapacity()
Returns ~2x the old capacity if small; ~1.5x otherwise.
|
(package private) int |
capacity() |
private static int |
capAtMaximumSize(int queueSize,
int maximumSize)
There's no reason for the queueSize to ever be more than maxSize + 1
|
void |
clear() |
java.util.Comparator<? super E> |
comparator()
Returns the comparator used to order the elements in this queue.
|
static <E extends java.lang.Comparable<E>> |
create()
Creates a new min-max priority queue with default settings: natural order,
no maximum size, no initial contents, and an initial expected size of 11.
|
static <E extends java.lang.Comparable<E>> |
create(java.lang.Iterable<? extends E> initialContents)
Creates a new min-max priority queue using natural order, no maximum size,
and initially containing the given elements.
|
(package private) E |
elementData(int index) |
static MinMaxPriorityQueue.Builder<java.lang.Comparable> |
expectedSize(int expectedSize)
Creates and returns a new builder, configured to build
MinMaxPriorityQueue instances sized appropriately to hold expectedSize elements. |
private MinMaxPriorityQueue.MoveDesc<E> |
fillHole(int index,
E toTrickle) |
private int |
getMaxElementIndex()
Returns the index of the max element.
|
private void |
growIfNeeded() |
private MinMaxPriorityQueue.Heap |
heapForIndex(int i) |
(package private) static int |
initialQueueSize(int configuredExpectedSize,
int maximumSize,
java.lang.Iterable<?> initialContents) |
(package private) static boolean |
isEvenLevel(int index) |
(package private) boolean |
isIntact()
Returns
true if the MinMax heap structure holds. |
java.util.Iterator<E> |
iterator()
Returns an iterator over the elements contained in this collection,
in no particular order.
|
static MinMaxPriorityQueue.Builder<java.lang.Comparable> |
maximumSize(int maximumSize)
Creates and returns a new builder, configured to build
MinMaxPriorityQueue instances that are limited to maximumSize
elements. |
boolean |
offer(E element)
Adds the given element to this queue.
|
static <B> MinMaxPriorityQueue.Builder<B> |
orderedBy(java.util.Comparator<B> comparator)
Creates and returns a new builder, configured to build
MinMaxPriorityQueue instances that use comparator to determine the
least and greatest elements. |
E |
peek() |
E |
peekFirst()
Retrieves, but does not remove, the least element of this queue, or returns
null if the queue is empty. |
E |
peekLast()
Retrieves, but does not remove, the greatest element of this queue, or
returns
null if the queue is empty. |
E |
poll() |
E |
pollFirst()
Removes and returns the least element of this queue, or returns
null if the queue is empty. |
E |
pollLast()
Removes and returns the greatest element of this queue, or returns
null if the queue is empty. |
private E |
removeAndGet(int index)
Removes and returns the value at
index . |
(package private) MinMaxPriorityQueue.MoveDesc<E> |
removeAt(int index)
Removes the element at position
index . |
E |
removeFirst()
Removes and returns the least element of this queue.
|
E |
removeLast()
Removes and returns the greatest element of this queue.
|
int |
size() |
java.lang.Object[] |
toArray() |
contains, containsAll, isEmpty, remove, removeAll, retainAll, toArray, toString
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
private final MinMaxPriorityQueue.Heap minHeap
private final MinMaxPriorityQueue.Heap maxHeap
final int maximumSize
private java.lang.Object[] queue
private int size
private int modCount
private static final int EVEN_POWERS_OF_TWO
private static final int ODD_POWERS_OF_TWO
private static final int DEFAULT_CAPACITY
private MinMaxPriorityQueue(MinMaxPriorityQueue.Builder<? super E> builder, int queueSize)
public static <E extends java.lang.Comparable<E>> MinMaxPriorityQueue<E> create()
public static <E extends java.lang.Comparable<E>> MinMaxPriorityQueue<E> create(java.lang.Iterable<? extends E> initialContents)
public static <B> MinMaxPriorityQueue.Builder<B> orderedBy(java.util.Comparator<B> comparator)
MinMaxPriorityQueue
instances that use comparator
to determine the
least and greatest elements.public static MinMaxPriorityQueue.Builder<java.lang.Comparable> expectedSize(int expectedSize)
MinMaxPriorityQueue
instances sized appropriately to hold expectedSize
elements.public static MinMaxPriorityQueue.Builder<java.lang.Comparable> maximumSize(int maximumSize)
MinMaxPriorityQueue
instances that are limited to maximumSize
elements. Each time a queue grows beyond this bound, it immediately
removes its greatest element (according to its comparator), which might be
the element that was just added.public int size()
public boolean add(E element)
element
the queue will automatically evict its
greatest element (according to its comparator), which may be element
itself.public boolean addAll(java.util.Collection<? extends E> newElements)
public boolean offer(E element)
element
the queue will automatically evict its
greatest element (according to its comparator), which may be element
itself.public E poll()
E elementData(int index)
public E peek()
private int getMaxElementIndex()
public E pollFirst()
null
if the queue is empty.public E removeFirst()
java.util.NoSuchElementException
- if the queue is emptypublic E peekFirst()
null
if the queue is empty.public E pollLast()
null
if the queue is empty.public E removeLast()
java.util.NoSuchElementException
- if the queue is emptypublic E peekLast()
null
if the queue is empty.MinMaxPriorityQueue.MoveDesc<E> removeAt(int index)
index
.
Normally this method leaves the elements at up to index - 1
,
inclusive, untouched. Under these circumstances, it returns null
.
Occasionally, in order to maintain the heap invariant, it must swap a
later element of the list with one before index
. Under these
circumstances it returns a pair of elements as a MinMaxPriorityQueue.MoveDesc
. The
first one is the element that was previously at the end of the heap and is
now at some position before index
. The second element is the one
that was swapped down to replace the element at index
. This fact is
used by iterator.remove so as to visit elements during a traversal once and
only once.
private MinMaxPriorityQueue.MoveDesc<E> fillHole(int index, E toTrickle)
private E removeAndGet(int index)
index
.private MinMaxPriorityQueue.Heap heapForIndex(int i)
static boolean isEvenLevel(int index)
boolean isIntact()
true
if the MinMax heap structure holds. This is only used
in testing.
TODO(kevinb): move to the test class?public java.util.Iterator<E> iterator()
The iterator is fail-fast: If the MinMaxPriorityQueue is modified
at any time after the iterator is created, in any way except through the
iterator's own remove method, the iterator will generally throw a
ConcurrentModificationException
. Thus, in the face of concurrent
modification, the iterator fails quickly and cleanly, rather than risking
arbitrary, non-deterministic behavior at an undetermined time in the
future.
Note that the fail-fast behavior of an iterator cannot be guaranteed
as it is, generally speaking, impossible to make any hard guarantees in the
presence of unsynchronized concurrent modification. Fail-fast iterators
throw ConcurrentModificationException
on a best-effort basis.
Therefore, it would be wrong to write a program that depended on this
exception for its correctness: the fail-fast behavior of iterators
should be used only to detect bugs.
public void clear()
public java.lang.Object[] toArray()
public java.util.Comparator<? super E> comparator()
PriorityQueue.comparator
, but returns Ordering.natural()
instead of null
to indicate natural ordering.int capacity()
static int initialQueueSize(int configuredExpectedSize, int maximumSize, java.lang.Iterable<?> initialContents)
private void growIfNeeded()
private int calculateNewCapacity()
private static int capAtMaximumSize(int queueSize, int maximumSize)