com.carrotsearch.hppcrt.heaps.CharIndexedHeapPriorityQueue Maven / Gradle / Ivy
package com.carrotsearch.hppcrt.heaps;
import java.util.*;
import com.carrotsearch.hppcrt.*;
import com.carrotsearch.hppcrt.cursors.*;
import com.carrotsearch.hppcrt.hash.BitMixer;
import com.carrotsearch.hppcrt.predicates.*;
import com.carrotsearch.hppcrt.procedures.*;
import com.carrotsearch.hppcrt.strategies.*;
/**
* A Heap-based, indexed min-priority queue of char
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 IntCharMap}, and acts like a (K,V) = (int, char) 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} occurs, the map may be resized to be able hold a key exceeding the current capacity.
*
*/
@javax.annotation.Generated(
date = "2017-07-11T19:16:22+0200",
value = "KTypeIndexedHeapPriorityQueue.java")
public class CharIndexedHeapPriorityQueue implements IntCharMap, Cloneable
{
/**
* 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 char []
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
*/
protected 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 CharComparator comparator;
protected char defaultValue = ('\u0000');
/**
* 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 CharIndexedHeapPriorityQueue(
CharComparator comp,
final int initialCapacity) {
this.comparator = comp;
//1-based index buffer, assure allocation
ensureBufferSpace(Math.max(Containers.DEFAULT_EXPECTED_ELEMENTS, initialCapacity));
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 = ((CharIndexedHeapPriorityQueue.this.buffer));
obj.size = CharIndexedHeapPriorityQueue.this.elementsCount;
obj.qp = CharIndexedHeapPriorityQueue.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
* {@link Containers#DEFAULT_EXPECTED_ELEMENTS} elements.
*
* @see BoundedProportionalArraySizingStrategy
*/
public CharIndexedHeapPriorityQueue( CharComparator comp
)
{
this(comp, Containers.DEFAULT_EXPECTED_ELEMENTS);
}
/**
* Default constructor: create with a default
* numbers of elements ({@link Containers#DEFAULT_EXPECTED_ELEMENTS}),
* using the natural ordering of char
s.
*/
public CharIndexedHeapPriorityQueue() {
this(null, Containers.DEFAULT_EXPECTED_ELEMENTS);
}
/**
* Create with an initial capacity,
* using the natural ordering of char
s
*/
public CharIndexedHeapPriorityQueue(final int initialCapacity) {
this(null, initialCapacity);
}
/**
* Create a indexed heap from all key-value pairs of another container.
*/
public CharIndexedHeapPriorityQueue(final IntCharAssociativeContainer container) {
this(container.size());
putAll(container);
}
/**
* Create a indexed heap from all key-value pairs of another container.. (constructor shortcut)
*/
public static CharIndexedHeapPriorityQueue from(final IntCharAssociativeContainer container) {
return new CharIndexedHeapPriorityQueue(container);
}
/**
* Creates a Indexed heap from two index-aligned arrays of key-value pairs.
*/
public static CharIndexedHeapPriorityQueue from(final int[] keys, final char[] values) {
if (keys.length != values.length) {
throw new IllegalArgumentException("Arrays of keys and values must have an identical length.");
}
final CharIndexedHeapPriorityQueue heap = new CharIndexedHeapPriorityQueue(keys.length);
for (int i = 0; i < keys.length; i++) {
heap.put(keys[i], values[i]);
}
return heap;
}
/**
* {@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 CharIndexedHeapPriorityQueue#iterator} entries.
* Holds a IntCharCursor returning
* (key, value, index) = (int key, char value, index the position in heap {@link CharIndexedHeapPriorityQueue#buffer}.)
*/
public final class EntryIterator extends AbstractIterator
{
public final IntCharCursor cursor;
private char[] buffer;
private int size;
private int[] qp;
public EntryIterator() {
this.cursor = new IntCharCursor();
//index 0 is not used in Priority queue
this.cursor.index = 0;
this.buffer = ((CharIndexedHeapPriorityQueue.this.buffer));
this.size = CharIndexedHeapPriorityQueue.this.size();
this.qp = CharIndexedHeapPriorityQueue.this.qp;
}
@Override
protected IntCharCursor 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 char[] 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 char[] 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 int removeAll(final IntCharPredicate predicate) {
final char[] buffer = ((this.buffer));
final int[] pq = this.pq;
final int size = this.elementsCount;
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++) {
final int pos = pq[key];
if (pos > 0 && predicate.apply(key, buffer[pos])) {
remove(key);
}
} //end for
return initialSize - this.elementsCount;
}
/**
* {@inheritDoc}
*/
@Override
public boolean putIfAbsent(final int key, final char value) {
if (!containsKey(key)) {
put(key, value);
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int putAll(final IntCharAssociativeContainer container) {
return putAll((Iterable extends IntCharCursor>) container);
}
/**
* {@inheritDoc}
*/
@Override
public int putAll(final Iterable extends IntCharCursor> iterable) {
final int count = this.elementsCount;
for (final IntCharCursor 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 IntCharMap#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}.
* @param key the integer key, must be >= 0
* @param element the associated value
*/
@Override
public char put(final int key, final char element) {
assert key >= 0 : "Keys must be >= 0, but is " + key;
//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 char 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;
}
/**
* If key
exists, putValue
is inserted into the map,
* otherwise any existing value is incremented by additionValue
.
*
* @param key
* The key of the value to adjust.
* @param putValue
* The value to put if key
does not exist.
* @param incrementValue
* The value to add to the existing value if key
exists.
* @return Returns the current value associated with key
(after
* changes).
*/
@SuppressWarnings("cast")
@Override
public char putOrAdd(final int key, char putValue, final char incrementValue) {
if (containsKey(key)) {
putValue = get(key);
putValue = (char) (((putValue) + (incrementValue)));
}
put(key, putValue);
return putValue;
}
/**
* Adds incrementValue
to any existing value for the given key
* or inserts incrementValue
if key
did not previously exist.
*
* @param key The key of the value to adjust.
* @param incrementValue 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 char addTo(final int key, final char incrementValue)
{
return putOrAdd(key, incrementValue, incrementValue);
}
/**
* 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 char top() {
char 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 char popTop() {
char elem = this.defaultValue;
if (this.elementsCount > 0) {
elem = ((this.buffer[1]));
remove(this.qp[1]);
}
return elem;
}
/**
* {@inheritDoc}
* cost: O(1)
*/
@Override
public char get(final int key) {
char 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))
*/
@SuppressWarnings("boxing")
@Override
public char remove(final int key) {
char deletedElement = this.defaultValue;
final int[] qp = this.qp;
final int[] pq = this.pq;
final char[] 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 char[] 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 + BitMixer.mix(index);
//append the rehash of the value
h = 31 * h + BitMixer.mix(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 the indexed heaps are considered equal as IntCharMap are.
*/
@Override
/* */
public boolean equals(final Object obj) {
if (obj != null) {
if (obj == this) {
return true;
}
//we can only compare both CharHeapPriorityQueue and not subclasses between themselves
//that has the same comparison function reference
if (obj.getClass() != this.getClass()) {
return false;
}
final CharIndexedHeapPriorityQueue other = (CharIndexedHeapPriorityQueue) obj;
if (other.size() != this.size()) {
return false;
}
//If one comparator is null, and the other not, we cannot compare them, same if
//both comparators are different because the heap behavior will be different, even elements are equal.
if (!((this.comparator == null && other.comparator == null) || (this.comparator != null && this.comparator.equals(other.comparator)))) {
return false;
}
//these are both maps, so iterate like maps !
final EntryIterator it = this.iterator();
while (it.hasNext()) {
final IntCharCursor c = it.next();
if (!other.containsKey(c.key)) {
//recycle
it.release();
return false;
}
final char mineValue = c.value;
final char otherValue = other.get(c.key);
if (!((mineValue) == (otherValue))) {
//recycle
it.release();
return false;
}
} //end while
return true;
}
return false;
}
/**
* Clone this object. The returned clone will use the same comparator.
*/
@Override
public CharIndexedHeapPriorityQueue clone() {
//placeholder container
final CharIndexedHeapPriorityQueue cloned = new CharIndexedHeapPriorityQueue(this.comparator,
Containers.DEFAULT_EXPECTED_ELEMENTS);
//clone raw buffers
cloned.buffer = this.buffer.clone();
cloned.pq = this.pq.clone();
cloned.qp = this.qp.clone();
cloned.defaultValue = this.defaultValue;
cloned.elementsCount = this.elementsCount;
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 KeysCollection view of the keys of this associated container.
* This view then reflects all changes from the heap.
*/
@Override
public KeysCollection keys() {
return new KeysCollection();
}
/**
* A view of the keys inside this Indexed heap.
*/
public final class KeysCollection extends AbstractIntCollection implements IntLookupContainer
{
private final CharIndexedHeapPriorityQueue owner = CharIndexedHeapPriorityQueue.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 removeAll(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 = CharIndexedHeapPriorityQueue.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 returning (value, index) = (int key, index the position in heap {@link CharIndexedHeapPriorityQueue#buffer}.)
*/
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 = CharIndexedHeapPriorityQueue.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 ValuesCollection, view of the values of this indexed heap.
* This view then reflects all changes from the heap.
*/
@Override
public ValuesCollection values() {
return new ValuesCollection();
}
/**
* A view over the set of values of this map.
*/
public final class ValuesCollection extends AbstractCharCollection
{
private final CharIndexedHeapPriorityQueue owner = CharIndexedHeapPriorityQueue.this;
private char currentOccurenceToBeRemoved;
private final CharPredicate removeAllOccurencesPredicate = new CharPredicate() {
@Override
public final boolean apply(final char value) {
if (((value) == (ValuesCollection.this.currentOccurenceToBeRemoved))) {
return true;
}
return false;
}
};
/**
* {@inheritDoc}
*/
@Override
public int size() {
return this.owner.size();
}
/**
* {@inheritDoc}
*/
@Override
public int capacity() {
return this.owner.capacity();
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(final char value) {
final char[] buffer = ((this.owner.buffer));
final int size = this.owner.elementsCount;
for (int pos = 1; pos <= size; pos++) {
if (((buffer[pos]) == (value))) {
return true;
}
}
return false;
}
@Override
public T forEach(final T procedure) {
final char[] 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 char[] 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.
*/
@Override
public int removeAll(final char 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 CharPredicate predicate) {
return this.owner.removeAllInternal(predicate);
}
/**
* {@inheritDoc}
* Alias for clear() the whole map.
*/
@Override
public void clear() {
this.owner.clear();
}
@Override
public char[] toArray(final char[] 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 = ((CharIndexedHeapPriorityQueue.this.buffer));
obj.size = CharIndexedHeapPriorityQueue.this.size();
}
@Override
public void reset(final ValuesIterator obj) {
obj.buffer = null;
}
});
}
/**
* An iterator over the set of assigned values.
* Holds a CharCursor returning (value, index) = (char value, index the position in heap {@link CharIndexedHeapPriorityQueue#buffer}.)
*/
public final class ValuesIterator extends AbstractIterator
{
public final CharCursor cursor;
private char[] buffer;
private int size;
public ValuesIterator() {
this.cursor = new CharCursor();
//index 0 is not used in Priority queue
this.cursor.index = 0;
this.buffer = ((CharIndexedHeapPriorityQueue.this.buffer));
this.size = size();
}
@Override
protected CharCursor 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 char[] 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"
*/
@Override
public char getDefaultValue() {
return this.defaultValue;
}
/**
* Set the "default value" value to be used
* in methods returning the "default value"
*/
@Override
public void setDefaultValue(final char 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 char
s is used instead
* */
public CharComparator
comparator() {
return this.comparator;
}
/**
* Ensures the internal buffer has enough free slots to accommodate the index
* index
. Increases internal buffer size if needed.
*/
@SuppressWarnings("boxing")
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 + Containers.DEFAULT_EXPECTED_ELEMENTS, (int) (index * 1.5));
try {
final int[] newPQIndex = new int[newPQSize];
final char[] newBuffer = (new char[(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;
} catch (final OutOfMemoryError e) {
throw new BufferAllocationException("Not enough memory to allocate buffers to grow from %d -> %d elements", e,
pqLen, newPQSize);
}
} //end if
}
/**
* Sink function for Comparable elements
*
* @param k
*/
private void sinkComparable(int k) {
final int N = this.elementsCount;
char tmp;
int child;
int indexK, indexChild;
final char[] 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 CharComparator elements
*
* @param k
*/
private void sinkComparator(int k) {
final int N = this.elementsCount;
char tmp;
int child;
int indexK, indexChild;
final char[] buffer = ((this.buffer));
final int[] pq = this.pq;
final int[] qp = this.qp;
CharComparator 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) {
char tmp;
int parent;
int indexK, indexParent;
final char[] 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) {
char tmp;
int parent;
int indexK, indexParent;
final char[] buffer = ((this.buffer));
final int[] pq = this.pq;
final int[] qp = this.qp;
CharComparator 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 CharPredicate predicate) {
//remove by position
int deleted = 0;
final char[] 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;
}
}