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

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 chars,
 * 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 chars. */ public CharIndexedHeapPriorityQueue() { this(null, Containers.DEFAULT_EXPECTED_ELEMENTS); } /** * Create with an initial capacity, * using the natural ordering of chars */ 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) container); } /** * {@inheritDoc} */ @Override public int putAll(final Iterable 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 chars 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy