com.carrotsearch.hppcrt.heaps.ShortIndexedHeapPriorityQueue Maven / Gradle / Ivy
Show all versions of hppcrt Show documentation
package com.carrotsearch.hppcrt.heaps;
import java.util.*;
import com.carrotsearch.hppcrt.*;
import com.carrotsearch.hppcrt.cursors.*;
import com.carrotsearch.hppcrt.predicates.*;
import com.carrotsearch.hppcrt.procedures.*;
import com.carrotsearch.hppcrt.strategies.*;
/**
* A Heap-based, indexed min-priority queue of short
s,
* i.e. top() is the smallest element of the queue.
* as defined by Sedgewick: Algorithms 4th Edition (2011).
* This class is also a {@link IntShortMap}, and acts like a (K,V) = (int, short) map with >= 0 keys.
* It assures O(log(N)) complexity for insertion, deletion, updating priorities,
* and constant time to examine the min element by {@link #top()} and for {@link #containsKey(int)}.
* Important:
* Ordering of elements must be defined either
* * by natural ordering
* * or by a custom comparator provided in constructors,
* see {@link #comparator()} .
*
*
Warning : This implementation uses direct indexing, meaning that a map
* at any given time is only able to have int
keys in
* the [0 ; {@link #capacity()}[ range. So when a {@link #put(int, short)} occurs, the map may be resized to be able hold a key exceeding the current capacity.
*
* @author Vincent Sonnier
*/
@javax.annotation.Generated(date = "2015-02-27T19:21:03+0100", value = "HPPC-RT generated from: ShortIndexedHeapPriorityQueue.java")
public class ShortIndexedHeapPriorityQueue implements IntShortMap, Cloneable
{
/**
* Default capacity if no other capacity is given in the constructor.
*/
public final static int DEFAULT_CAPACITY = 16;
/**
* Internal array for storing the priority queue
*
* Direct indexed priority queue iteration: iterate pq[i] for i in [0; pq.length[
* and buffer[pq[i]] to get value where pq[i] > 0
*
*/
public short[] buffer;
/**
* Internal array for storing index to buffer position matching
* i.e for an index i, pq[i] is the position of element in priority queue buffer.
*
* Direct iteration: iterate pq[i] for indices i in [0; pq.length[
* where pq[i] > 0, then buffer[pq[i]] is the value associated with index i.
*
*/
public int[] pq;
/**
* Internal array pq inversing :
* i.e for a priority buffer position pos, qp[pos] is the index of the value.,
* ie qp[pq|i]] = i
*/
public int[] qp;
/**
* Number of elements in the queue.
*/
protected int elementsCount;
/**
* Defines the Comparator ordering of the queue,
* If null, natural ordering is used.
*/
protected ShortComparator comparator;
protected short defaultValue = ((short)0);
/**
* internal pool of EntryIterator (must be created in constructor)
*/
protected final IteratorPool entryIteratorPool;
/**
* Create with a given initial capacity, using a
* Comparator for ordering.
*/
public ShortIndexedHeapPriorityQueue( ShortComparator comp,
final int initialCapacity)
{
this.comparator = comp;
assert initialCapacity >= 0 : "initialCapacity must be >= 0: " + initialCapacity;
//1-based index buffer, assure allocation
ensureBufferSpace(initialCapacity + 1);
this.entryIteratorPool = new IteratorPool(
new ObjectFactory() {
@Override
public EntryIterator create()
{
return new EntryIterator();
}
@Override
public void initialize(final EntryIterator obj)
{
obj.cursor.index = 0;
obj.buffer = ShortIndexedHeapPriorityQueue.this.buffer;
obj.size = ShortIndexedHeapPriorityQueue.this.elementsCount;
obj.qp = ShortIndexedHeapPriorityQueue.this.qp;
}
@Override
public void reset(final EntryIterator obj)
{
// for GC sake
obj.qp = null;
obj.buffer = null;
}
});
}
/**
* Create with default sizing strategy and initial capacity for storing
* {@value #DEFAULT_CAPACITY} elements.
*
* @see BoundedProportionalArraySizingStrategy
*/
public ShortIndexedHeapPriorityQueue( ShortComparator comp
)
{
this(comp, ShortIndexedHeapPriorityQueue.DEFAULT_CAPACITY);
}
/**
* Create with an initial capacity,
* using the natural ordering of short
s
*/
public ShortIndexedHeapPriorityQueue(final int initialCapacity)
{
this(null, initialCapacity);
}
/**
* {@inheritDoc}
*/
@Override
public void clear()
{
//we need to init to zero, not -1 !!!
Arrays.fill(this.pq, 0);
//This is not really needed to reset this,
//but is useful to catch inconsistencies in assertions
this.elementsCount = 0;
}
/**
* An iterator implementation for {@link ShortIndexedHeapPriorityQueue#iterator} entries.
* Holds a IntShortCursor cursor returning (key, value, index) = (int key, short value, index the position in heap)
*/
public final class EntryIterator extends AbstractIterator
{
public final IntShortCursor cursor;
private short[] buffer;
private int size;
private int[] qp;
public EntryIterator()
{
this.cursor = new IntShortCursor();
//index 0 is not used in Priority queue
this.cursor.index = 0;
this.buffer = ShortIndexedHeapPriorityQueue.this.buffer;
this.size = ShortIndexedHeapPriorityQueue.this.size();
this.qp = ShortIndexedHeapPriorityQueue.this.qp;
}
@Override
protected IntShortCursor fetch()
{
//priority is 1-based index
if (this.cursor.index == this.size)
{
return done();
}
//this.cursor.index represent the position in the heap buffer.
this.cursor.key = this.qp[++this.cursor.index];
this.cursor.value = this.buffer[this.cursor.index];
return this.cursor;
}
}
/**
* {@inheritDoc}
*/
@Override
public EntryIterator iterator()
{
return this.entryIteratorPool.borrow();
}
/**
* {@inheritDoc}
*/
@Override
public int size()
{
return this.elementsCount;
}
/**
* {@inheritDoc}
*/
@Override
public int capacity()
{
return this.buffer.length - 1;
}
/**
* {@inheritDoc}
*/
@Override
public T forEach(final T procedure)
{
final short[] buffer = this.buffer;
final int[] qp = this.qp;
final int size = this.elementsCount;
for (int pos = 1; pos <= size; pos++)
{
procedure.apply(qp[pos], buffer[pos]);
}
return procedure;
}
/**
* {@inheritDoc}
*/
@Override
public T forEach(final T predicate)
{
final short[] buffer = this.buffer;
final int[] qp = this.qp;
final int size = this.elementsCount;
for (int pos = 1; pos <= size; pos++)
{
if (!predicate.apply(qp[pos], buffer[pos]))
{
break;
}
}
return predicate;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty()
{
return this.elementsCount == 0;
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(final IntContainer container)
{
final int before = this.elementsCount;
for (final IntCursor cursor : container)
{
remove(cursor.value);
}
return before - this.elementsCount;
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(final IntPredicate predicate)
{
final int[] pq = this.pq;
final int size = this.pq.length;
final int initialSize = this.elementsCount;
//iterate keys, for all valid keys is OK because only the current pq[key] slot
//is affected by the current remove() but the next ones are not.
for (int key = 0; key < size; key++)
{
if (pq[key] > 0 && predicate.apply(key))
{
remove(key);
}
} //end for
return initialSize - this.elementsCount;
}
/**
* {@inheritDoc}
*/
@Override
public boolean putIfAbsent(final int key, final short value)
{
if (!containsKey(key))
{
put(key, value);
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int putAll(final IntShortAssociativeContainer container)
{
return putAll((Iterable extends IntShortCursor>) container);
}
/**
* {@inheritDoc}
*/
@Override
public int putAll(final Iterable extends IntShortCursor> iterable)
{
final int count = this.elementsCount;
for (final IntShortCursor c : iterable)
{
put(c.key, c.value);
}
return this.elementsCount - count;
}
/**
* {@inheritDoc}
* cost: O(log(N)) for a N sized queue
* Important:
* Whenever a new (key, value) pair is inserted, or
* a value is updated with an already present key as specified by the {@link IntShortMap#put()}
* contract, the inserted value priority is always consistent towards the comparison criteria.
* In other words, there is no need to call {@link #updatePriority(int)} after a {@link #put(int, short)}.
* @param key the integer key, must be >= 0
* @param element the associated value
*/
@Override
public short put(final int key, final short element)
{
assert key >= 0 : "Keys must be >= 0";
//1) Key already present, insert new value
if (key < this.pq.length && this.pq[key] > 0)
{
//element already exists : insert brutally at the same position in buffer and refresh the priorities to reestablish heap
final short previousValue = this.buffer[this.pq[key]];
this.buffer[this.pq[key]] = element;
//re-establish heap
sink(this.pq[key]);
swim(this.pq[key]);
return previousValue;
}
//2) not present, add at the end
// 2-1) pq must be sufficient to receive index by direct indexing,
//resize if needed.
ensureBufferSpace(key);
//2-2) Add
this.elementsCount++;
final int count = this.elementsCount;
this.buffer[count] = element;
//initial position
this.pq[key] = count;
this.qp[count] = key;
//swim last element
swim(count);
return this.defaultValue;
}
/**
* Trove-inspired API method. An equivalent
* of the following code:
*
* if (containsKey(key))
* {
* short v = get(key) + additionValue;
* put(key, v);
* return v;
* }
* else
* {
* put(key, putValue);
* return putValue;
* }
*
*
* @param key The key of the value to adjust.
* @param putValue The value to put if key
does not exist.
* @param additionValue The value to add to the existing value if key
exists.
* @return Returns the current value associated with key
(after changes).
*/
@Override
public short putOrAdd(int key, short putValue, short additionValue)
{
assert key >= 0;
//1) Key already present, add additionValue to the existing one
if (key < this.pq.length && this.pq[key] > 0)
{
//element already exists : insert brutally at the same position in buffer and refresh the priorities to reestablish heap
this.buffer[this.pq[key]] += additionValue;
//re-establish heap
sink(this.pq[key]);
swim(this.pq[key]);
return this.buffer[this.pq[key]];
}
//2) not present, add at the end
// 2-1) pq must be sufficient to receive index by direct indexing,
//resize if needed.
ensureBufferSpace(key);
//2-2) Add
this.elementsCount++;
final int count = this.elementsCount;
this.buffer[count] = putValue;
//initial position
this.pq[key] = count;
this.qp[count] = key;
//swim last element
swim(count);
return putValue;
}
/**
* An equivalent of calling
*
* if (containsKey(key))
* {
* short v = get(key) + additionValue;
* put(key, v);
* return v;
* }
* else
* {
* put(key, additionValue);
* return additionValue;
* }
*
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if key
exists.
* @return Returns the current value associated with key
(after changes).
*/
@Override
public short addTo(int key, short additionValue)
{
return putOrAdd(key, additionValue, additionValue);
}
/**
* Retrieve, but not remove, the top element of the queue,
* i.e. the min. element with respect to the comparison criteria
* of the queue. Returns the default value if empty.
* cost: O(1)
*/
public short top()
{
short elem = this.defaultValue;
if (this.elementsCount > 0)
{
elem = this.buffer[1];
}
return elem;
}
/**
* Retrieve the key corresponding to the top element of the queue,
* i.e. the min element with respect to the comparison criteria
* of the queue. Returns -1 if empty.
* cost: O(1)
*/
public int topKey()
{
int key = -1;
if (this.elementsCount > 0)
{
key = this.qp[1];
}
return key;
}
/**
* Retrieve, and remove the top element of the queue,
* i.e. the min/max element with respect to the comparison criteria
* (implementation defined) Returns the default value if empty.
* cost: O(log(N)) for a N sized queue
*/
public short popTop()
{
short elem = this.defaultValue;
if (this.elementsCount > 0)
{
elem = this.buffer[1];
remove(this.qp[1]);
}
return elem;
}
/**
* {@inheritDoc}
* cost: O(1)
*/
@Override
public short get(final int key)
{
short elem = this.defaultValue;
if (key < this.pq.length && this.pq[key] > 0)
{
elem = this.buffer[this.pq[key]];
}
return elem;
}
/**
* {@inheritDoc}
* cost: O(log(N))
*/
@Override
public short remove(final int key)
{
short deletedElement = this.defaultValue;
final int[] qp = this.qp;
final int[] pq = this.pq;
final short[] buffer = this.buffer;
if (key < pq.length && pq[key] > 0)
{
final int deletedPos = pq[key];
deletedElement = buffer[deletedPos];
if (deletedPos == this.elementsCount)
{
//we remove the last element
pq[key] = 0;
//for GC
//Not really needed, but usefull to catch inconsistencies
//diminuish size
this.elementsCount--;
}
else
{
//We are not removing the last element
final int lastElementIndex = qp[this.elementsCount];
//not needed, overwritten below :
buffer[deletedPos] = buffer[this.elementsCount];
//last element is now at pos deletedPos
pq[lastElementIndex] = deletedPos;
qp[deletedPos] = lastElementIndex;
//mark the index element to be removed
//we must reset with 0 so that qp[pq[index]] is always valid !
pq[key] = 0;
//Not really needed, but usefull to catch inconsistencies
//for GC
//diminuish size
this.elementsCount--;
//after swapping positions
if (this.elementsCount > 1)
{
//re-establish heap
sink(pq[lastElementIndex]);
swim(pq[lastElementIndex]);
}
}
}
return deletedElement;
}
/**
* Update the priority of the value associated with key, to re-establish the value correct priority
* towards the comparison criteria.
* cost: O(log(N))
*/
public void updatePriority(final int key)
{
if (key < this.pq.length && this.pq[key] > 0)
{
swim(this.pq[key]);
sink(this.pq[key]);
}
}
/**
* Update the priority of the {@link #top()} element, to re-establish its actual priority
* towards the comparison criteria when it may have changed such that it is no longer the
* min element with respect to the comparison criteria.
* cost: O(log(N))
*/
public void updateTopPriority()
{
//only attempt to sink if there is at least 2 elements....
if (this.elementsCount > 1) {
sink(1);
}
}
/**
* {@inheritDoc}
* cost: O(1)
*/
@Override
public boolean containsKey(final int key)
{
if (key < this.pq.length && this.pq[key] > 0)
{
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
int h = 1;
final int size = this.pq.length;
final short[] buffer = this.buffer;
final int[] pq = this.pq;
//iterate by (ordered) index to have a reproducible hash and
//so keeping a multiplicative quality
for (int index = 0; index < size; index++)
{
if (pq[index] > 0)
{
//rehash of the index
h = 31 * h + Internals.rehash(index);
//append the rehash of the value
h = 31 * h + Internals.rehash(buffer[pq[index]]);
}
}
return h;
}
/**
* this instance and obj can only be equal if either:
* (both don't have set comparators)
* or
* (both have equal comparators defined by {@link #comparator}.equals(obj.comparator))
* then, both heaps are compared as follows:
* {@inheritDoc}
*/
@Override
/* */
public boolean equals(final Object obj)
{
if (obj != null)
{
if (obj == this)
{
return true;
}
//we can only compare both ShortHeapPriorityQueue,
//that has the same comparison function reference
if (!(obj instanceof ShortIndexedHeapPriorityQueue))
{
return false;
}
final ShortIndexedHeapPriorityQueue other = (ShortIndexedHeapPriorityQueue) obj;
if (other.size() != this.size())
{
return false;
}
//Iterate over the smallest pq buffer of the two.
int[] pqBuffer, otherPqBuffer;
short[] buffer, otherBuffer;
if (this.pq.length < other.pq.length)
{
pqBuffer = this.pq;
otherPqBuffer = other.pq;
buffer = this.buffer;
otherBuffer = other.buffer;
}
else
{
pqBuffer = other.pq;
otherPqBuffer = this.pq;
buffer = other.buffer;
otherBuffer = this.buffer;
}
final int pqBufferSize = pqBuffer.length;
final short currentValue, otherValue;
int currentIndex, otherIndex;
//Both have null comparators
if (this.comparator == null && other.comparator == null)
{
for (int i = 0; i < pqBufferSize; i++)
{
currentIndex = pqBuffer[i];
if (currentIndex > 0)
{
//check that currentIndex exists in otherBuffer at the same i
otherIndex = otherPqBuffer[i];
if (otherIndex <= 0)
{
return false;
}
//compare both elements with Comparable, or natural ordering
if (!(buffer[currentIndex] == otherBuffer[otherIndex]))
{
return false;
}
}
}
return true;
}
else if (this.comparator != null && this.comparator.equals(other.comparator))
{
ShortComparator comp = this.comparator;
for (int i = 0; i < pqBufferSize; i++)
{
currentIndex = pqBuffer[i];
if (currentIndex > 0)
{
//check that currentIndex exists in otherBuffer
otherIndex = otherPqBuffer[i];
if (otherIndex <= 0)
{
return false;
}
//compare both elements with Comparator
if (comp.compare(buffer[i], otherBuffer[i]) != 0)
{
return false;
}
}
} //end for
return true;
} //end else comparator
}
return false;
}
/**
* Clone this object. The returned clone will use the same comparator.
* It also realizes a trim-to- this.size() in the process.
*/
@Override
public ShortIndexedHeapPriorityQueue clone()
{
final ShortIndexedHeapPriorityQueue cloned = new ShortIndexedHeapPriorityQueue(this.comparator, this.size());
for (final IntShortCursor cursor : this)
{
cloned.put(cursor.index, cursor.value);
}
cloned.defaultValue = this.defaultValue;
return cloned;
}
/**
* Update priorities of all the elements of the queue, to re-establish the correct priorities
* towards the comparison criteria.
* cost: O(n*log(N))
*/
public void updatePriorities()
{
if (this.comparator == null)
{
for (int k = this.elementsCount >> 1; k >= 1; k--)
{
sinkComparable(k);
}
}
else
{
for (int k = this.elementsCount >> 1; k >= 1; k--)
{
sinkComparator(k);
}
}
}
/**
* @return a new KeysContainer view of the keys of this associated container.
* This view then reflects all changes from the map.
*/
@Override
public KeysContainer keys()
{
return new KeysContainer();
}
/**
* A view of the keys inside this hash map.
*/
public final class KeysContainer extends AbstractIntCollection implements IntLookupContainer
{
private final ShortIndexedHeapPriorityQueue owner =
ShortIndexedHeapPriorityQueue.this;
@Override
public boolean contains(final int e)
{
return this.owner.containsKey(e);
}
@Override
public T forEach(final T procedure)
{
final int[] qp = this.owner.qp;
final int size = this.owner.elementsCount;
for (int pos = 1; pos <= size; pos++)
{
procedure.apply(qp[pos]);
}
return procedure;
}
@Override
public T forEach(final T predicate)
{
final int[] qp = this.owner.qp;
final int size = this.owner.elementsCount;
for (int pos = 1; pos <= size; pos++)
{
if (!predicate.apply(qp[pos]))
{
break;
}
}
return predicate;
}
/**
* {@inheritDoc}
*/
@Override
public KeysIterator iterator()
{
//return new KeysIterator();
return this.keyIteratorPool.borrow();
}
/**
* {@inheritDoc}
*/
@Override
public int size()
{
return this.owner.size();
}
/**
* {@inheritDoc}
*/
@Override
public int capacity()
{
return this.owner.capacity();
}
@Override
public void clear()
{
this.owner.clear();
}
@Override
public int removeAll(final IntPredicate predicate)
{
return this.owner.removeAll(predicate);
}
@Override
public int removeAllOccurrences(final int e)
{
final boolean hasKey = this.owner.containsKey(e);
int result = 0;
if (hasKey)
{
this.owner.remove(e);
result = 1;
}
return result;
}
@Override
public int[] toArray(final int[] target)
{
int count = 0;
final int[] pq = this.owner.pq;
final int size = this.owner.pq.length;
for (int key = 0; key < size; key++) {
if (pq[key] > 0) {
target[count] = key;
count++;
}
}
return target;
}
/**
* internal pool of KeysIterator
*/
protected final IteratorPool keyIteratorPool = new IteratorPool(
new ObjectFactory() {
@Override
public KeysIterator create()
{
return new KeysIterator();
}
@Override
public void initialize(final KeysIterator obj)
{
obj.cursor.value = -1;
obj.pq = ShortIndexedHeapPriorityQueue.this.pq;
}
@Override
public void reset(final KeysIterator obj)
{
//no dangling references
obj.pq = null;
}
});
};
/**
* An iterator over the set of assigned keys.
* Holds a IntCursor cursor returning (value, index) = (int key, index the position in heap)
*/
public final class KeysIterator extends AbstractIterator
{
public final IntCursor cursor;
private int[] pq;
public KeysIterator()
{
this.cursor = new IntCursor();
this.cursor.value = -1;
this.pq = ShortIndexedHeapPriorityQueue.this.pq;
}
/**
*
*/
@Override
protected IntCursor fetch()
{
//iterate next() : first iteration starts indeed at 0
int i = this.cursor.value + 1;
while (i < this.pq.length && this.pq[i] <= 0)
{
i++;
}
if (i == this.pq.length) {
return done();
}
//the cursor index corresponds to the position in heap buffer
this.cursor.value = i;
this.cursor.index = this.pq[i];
return this.cursor;
}
}
/**
* @return a new ValuesContainer, view of the values of this map.
* This view then reflects all changes from the map.
*/
@Override
public ValuesContainer values()
{
return new ValuesContainer();
}
/**
* A view over the set of values of this map.
*/
public final class ValuesContainer extends AbstractShortCollection
{
private final ShortIndexedHeapPriorityQueue owner =
ShortIndexedHeapPriorityQueue.this;
private short currentOccurenceToBeRemoved;
private final ShortPredicate removeAllOccurencesPredicate = new ShortPredicate() {
@Override
public final boolean apply(final short value) {
if (ValuesContainer.this.owner.comparator == null) {
if ((value == ValuesContainer.this.currentOccurenceToBeRemoved)) {
return true;
}
}
else {
if (ValuesContainer.this.owner.comparator.compare(value, ValuesContainer.this.currentOccurenceToBeRemoved) == 0) {
return true;
}
}
return false;
}
};
/**
* {@inheritDoc}
*/
@Override
public int size()
{
return this.owner.size();
}
/**
* {@inheritDoc}
*/
@Override
public int capacity()
{
return this.owner.capacity();
}
/**
* {@inheritDoc}
* Note : The comparison criteria for
* identity test is based on
* * natural ordering if no
* * custom comparator is given, else it uses the {@link #comparator()} criteria.
*/
@Override
public boolean contains(final short value)
{
final short[] buffer = this.owner.buffer;
final int size = this.owner.elementsCount;
if (this.owner.comparator == null) {
//iterate the heap buffer, use the natural comparison criteria
for (int pos = 1; pos <= size; pos++)
{
if ((buffer[pos] == value))
{
return true;
}
}
}
else {
//use the dedicated comparator
ShortComparator comp = this.owner.comparator;
for (int pos = 1; pos <= size; pos++)
{
if (comp.compare(ShortIndexedHeapPriorityQueue.this.buffer[pos], value) == 0)
{
return true;
}
}
} //end else
return false;
}
@Override
public T forEach(final T procedure)
{
final short[] buffer = this.owner.buffer;
final int size = this.owner.elementsCount;
//iterate the heap buffer, use the natural comparison criteria
for (int pos = 1; pos <= size; pos++)
{
procedure.apply(buffer[pos]);
}
return procedure;
}
@Override
public T forEach(final T predicate)
{
final short[] buffer = this.owner.buffer;
final int size = this.owner.elementsCount;
//iterate the heap buffer, use the natural comparison criteria
for (int pos = 1; pos <= size; pos++)
{
if (!predicate.apply(buffer[pos])) {
break;
}
}
return predicate;
}
@Override
public ValuesIterator iterator()
{
// return new ValuesIterator();
return this.valuesIteratorPool.borrow();
}
/**
* {@inheritDoc}
* Indeed removes all the (key,value) pairs matching
* (key ? , e) with the same e, from the map.
* Note : The comparison criteria for
* identity test is based on
* ! * natural ordering if no
* * custom comparator is given, else it uses the {@link #comparator()} criteria.
*/
@Override
public int removeAllOccurrences(final short e)
{
this.currentOccurenceToBeRemoved = e;
return this.owner.removeAllInternal(this.removeAllOccurencesPredicate);
}
/**
* {@inheritDoc}
* Indeed removes all the (key,value) pairs matching
* the predicate for the values, from the map.
*/
@Override
public int removeAll(final ShortPredicate predicate)
{
return this.owner.removeAllInternal(predicate);
}
/**
* {@inheritDoc}
* Alias for clear() the whole map.
*/
@Override
public void clear()
{
this.owner.clear();
}
@Override
public short[] toArray(final short[] target)
{
//buffer validity starts at 1
System.arraycopy(this.owner.buffer, 1, target, 0, this.owner.elementsCount);
return target;
}
/**
* internal pool of ValuesIterator
*/
protected final IteratorPool valuesIteratorPool = new IteratorPool(
new ObjectFactory() {
@Override
public ValuesIterator create()
{
return new ValuesIterator();
}
@Override
public void initialize(final ValuesIterator obj)
{
obj.cursor.index = 0;
obj.buffer = ShortIndexedHeapPriorityQueue.this.buffer;
obj.size = ShortIndexedHeapPriorityQueue.this.size();
}
@Override
public void reset(final ValuesIterator obj)
{
obj.buffer = null;
}
});
}
/**
* An iterator over the set of assigned values.
* Holds a ShortCursor cursor returning (value, index) = (short value, index the position in heap)
*/
public final class ValuesIterator extends AbstractIterator
{
public final ShortCursor cursor;
private short[] buffer;
private int size;
public ValuesIterator()
{
this.cursor = new ShortCursor();
//index 0 is not used in Priority queue
this.cursor.index = 0;
this.buffer = ShortIndexedHeapPriorityQueue.this.buffer;
this.size = size();
}
@Override
protected ShortCursor fetch()
{
//priority is 1-based index
if (this.cursor.index == this.size)
{
return done();
}
//this.cursor.index represent the position in the heap buffer.
this.cursor.value = this.buffer[++this.cursor.index];
return this.cursor;
}
}
@Override
public String toString()
{
final short[] buffer = this.buffer;
final int[] pq = this.pq;
final StringBuilder buff = new StringBuilder();
buff.append("[");
boolean first = true;
//Indices are displayed in ascending order, for easier reading.
for (int i = 0; i < pq.length; i++)
{
if (pq[i] > 0)
{
if (!first)
{
buff.append(", ");
}
buff.append(i);
buff.append("=>");
buff.append(buffer[pq[i]]);
first = false;
}
}
buff.append("]");
return buff.toString();
}
/**
* Returns the "default value" value used
* in methods returning "default value"
* @return
*/
public short getDefaultValue()
{
return this.defaultValue;
}
/**
* Set the "default value" value to be used
* in methods returning the "default value"
* @return
*/
public void setDefaultValue(final short defaultValue)
{
this.defaultValue = defaultValue;
}
/**
* Get the custom comparator used for comparing elements
* @return null if no custom comparator was set, i.e natural ordering
* of short
s is used instead
* */
public ShortComparator
comparator() {
return this.comparator;
}
/**
* Ensures the internal buffer has enough free slots to accomodate the index
* index
. Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(final int index)
{
final int pqLen = this.pq == null ? 0 : this.pq.length;
if (index > pqLen - 1)
{
//resize to accomodate this index: use a 50% grow to mitigate when the user
//has not presized properly the container.
final int newPQSize = Math.max(index + ShortIndexedHeapPriorityQueue.DEFAULT_CAPACITY, (int) (index * 1.5));
final int[] newPQIndex = new int[newPQSize];
final short[] newBuffer = (new short[newPQSize + 1]);
final int[] newQPIndex = new int[newPQSize + 1];
if (pqLen > 0)
{
System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length);
System.arraycopy(this.pq, 0, newPQIndex, 0, this.pq.length);
System.arraycopy(this.qp, 0, newQPIndex, 0, this.qp.length);
}
this.buffer = newBuffer;
this.pq = newPQIndex;
this.qp = newQPIndex;
}
}
/**
* Sink function for Comparable elements
* @param k
*/
private void sinkComparable(int k)
{
final int N = this.elementsCount;
short tmp;
int child;
int indexK, indexChild;
final short[] buffer = this.buffer;
final int[] pq = this.pq;
final int[] qp = this.qp;
while (k << 1 <= N)
{
//get the child of k
child = k << 1;
if (child < N && (buffer[child] > buffer[child + 1]))
{
child++;
}
if (!(buffer[k] > buffer[child]))
{
break;
}
//swap k and child
tmp = buffer[k];
buffer[k] = buffer[child];
buffer[child] = tmp;
//swap references
indexK = qp[k];
indexChild = qp[child];
pq[indexK] = child;
pq[indexChild] = k;
qp[k] = indexChild;
qp[child] = indexK;
k = child;
} //end while
}
/**
* Sink function for ShortComparator elements
* @param k
*/
private void sinkComparator(int k)
{
final int N = this.elementsCount;
short tmp;
int child;
int indexK, indexChild;
final short[] buffer = this.buffer;
final int[] pq = this.pq;
final int[] qp = this.qp;
ShortComparator comp = this.comparator;
while (k << 1 <= N)
{
//get the child of k
child = k << 1;
if (child < N && comp.compare(buffer[child], buffer[child + 1]) > 0)
{
child++;
}
if (comp.compare(buffer[k], buffer[child]) <= 0)
{
break;
}
//swap k and child
tmp = buffer[k];
buffer[k] = buffer[child];
buffer[child] = tmp;
//swap references
indexK = qp[k];
indexChild = qp[child];
pq[indexK] = child;
pq[indexChild] = k;
qp[k] = indexChild;
qp[child] = indexK;
k = child;
} //end while
}
/**
* Swim function for Comparable elements
* @param k
*/
private void swimComparable(int k)
{
short tmp;
int parent;
int indexK, indexParent;
final short[] buffer = this.buffer;
final int[] pq = this.pq;
final int[] qp = this.qp;
while (k > 1 && (buffer[k >> 1] > buffer[k]))
{
//swap k and its parent
parent = k >> 1;
//swap k and parent
tmp = buffer[k];
buffer[k] = buffer[parent];
buffer[parent] = tmp;
//swap references
indexK = qp[k];
indexParent = qp[parent];
pq[indexK] = parent;
pq[indexParent] = k;
qp[k] = indexParent;
qp[parent] = indexK;
k = parent;
}
}
/**
* Swim function for Comparator elements
* @param k
*/
private void swimComparator(int k)
{
short tmp;
int parent;
int indexK, indexParent;
final short[] buffer = this.buffer;
final int[] pq = this.pq;
final int[] qp = this.qp;
ShortComparator comp = this.comparator;
while (k > 1 && comp.compare(buffer[k >> 1], buffer[k]) > 0)
{
//swap k and its parent
parent = k >> 1;
//swap k and parent
tmp = buffer[k];
buffer[k] = buffer[parent];
buffer[parent] = tmp;
//swap references
indexK = qp[k];
indexParent = qp[parent];
pq[indexK] = parent;
pq[indexParent] = k;
qp[k] = indexParent;
qp[parent] = indexK;
k = parent;
}
}
private void swim(final int k)
{
if (this.comparator == null)
{
swimComparable(k);
}
else
{
swimComparator(k);
}
}
private void sink(final int k)
{
if (this.comparator == null)
{
sinkComparable(k);
}
else
{
sinkComparator(k);
}
}
private int removeAllInternal(final ShortPredicate predicate)
{
//remove by position
int deleted = 0;
final short[] buffer = this.buffer;
final int[] qp = this.qp;
final int[] pq = this.pq;
int lastElementIndex = -1;
int elementsCount = this.elementsCount;
//1-based index
int pos = 1;
try
{
while (pos <= elementsCount)
{
//delete it
if (predicate.apply(buffer[pos]))
{
lastElementIndex = qp[elementsCount];
//put the last element at position pos, like in remove()
buffer[pos] = buffer[elementsCount];
//last element is now at deleted position pos
pq[lastElementIndex] = pos;
//mark the index element to be removed
//we must reset with 0 so that qp[pq[index]] is always valid !
pq[qp[pos]] = 0;
qp[pos] = lastElementIndex;
//Not really needed
//for GC
//Diminish size
elementsCount--;
deleted++;
} //end if to delete
else
{
pos++;
}
} //end while
//At that point, heap property is not OK, but we are consistent nonetheless.
}
finally
{
this.elementsCount = elementsCount;
//reestablish heap
updatePriorities();
}
return deleted;
}
}