All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.carrotsearch.hppcrt.heaps.ShortIndexedHeapPriorityQueue Maven / Gradle / Ivy

Go to download

High Performance Primitive Collections Realtime (fork of HPPC of Carrotsearch) Fundamental data structures (maps, sets, lists, stacks, queues, heaps, sorts) generated for combinations of object and primitive types to conserve JVM memory and speed up execution. The Realtime fork intend of extending collections while tweaking and optimizations to remove any dynamic allocations at runtime, and low variance execution times.

There is a newer version: 0.7.5
Show newest version
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 shorts,
 * 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 shorts */ 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) container); } /** * {@inheritDoc} */ @Override public int putAll(final Iterable 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 shorts 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; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy