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

com.carrotsearch.hppcrt.heaps.ObjectHeapPriorityQueue 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, min-priority queue of KTypes.
 * i.e. top() is the smallest element,
 * as defined by Sedgewick: Algorithms 4th Edition (2011).
 * It assure O(log(N)) complexity for insertion,  deletion and update priority of the min element,
 * and constant time to examine the min element by {@link #top()}.
 * 

Important: * Ordering of elements must be defined either * * by {@link Comparable} * * or by a custom comparator provided in constructors, * see {@link #comparator()} . * @author Vincent Sonnier */ @javax.annotation.Generated(date = "2015-02-27T19:21:03+0100", value = "HPPC-RT generated from: ObjectHeapPriorityQueue.java") public class ObjectHeapPriorityQueue extends AbstractObjectCollection implements ObjectPriorityQueue, 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. *

Important! * The actual value in this field is always an instance of Object[]. * Be warned that javac emits additional casts when buffer * is directly accessed; these casts * may result in exceptions at runtime. A workaround is to cast directly to * Object[] before accessing the buffer's elements (although it is highly * recommended to use a {@link #iterator()} instead. *

*

* Direct priority queue iteration: iterate buffer[i] for i in [1; size()] (included) but is out-of-order w.r.t {@link #popTop()} *

*/ public KType[] buffer; /** * Number of elements in the queue. */ protected int elementsCount; /** * Defines the Comparator ordering of the queue, * If null, natural ordering is used. */ protected Comparator comparator; /** * Buffer resizing strategy. */ protected final ArraySizingStrategy resizer; /** * internal pool of ValueIterator (must be created in constructor) */ protected final IteratorPool, ValueIterator> valueIteratorPool; /** * The current value set for removeAll */ private KType currentOccurenceToBeRemoved; /** * Internal predicate for removeAll */ private final ObjectPredicate removeAllOccurencesPredicate = new ObjectPredicate() { @Override public final boolean apply(final KType value) { if (ObjectHeapPriorityQueue.this.comparator == null) { if ((((Comparable) value).compareTo(ObjectHeapPriorityQueue.this.currentOccurenceToBeRemoved) == 0)) { return true; } } else { if (ObjectHeapPriorityQueue.this.comparator.compare(value, ObjectHeapPriorityQueue.this.currentOccurenceToBeRemoved) == 0) { return true; } } return false; } }; /** * Create with a Comparator, an initial capacity, and a custom buffer resizing strategy. */ public ObjectHeapPriorityQueue( final Comparator comp, final int initialCapacity, final ArraySizingStrategy resizer) { this.comparator = comp; assert initialCapacity >= 0 : "initialCapacity must be >= 0: " + initialCapacity; assert resizer != null; this.resizer = resizer; //1-based index buffer, assure allocation final int internalSize = resizer.round(initialCapacity); this.buffer = (Internals.newArray(internalSize + 1)); this.valueIteratorPool = new IteratorPool, ValueIterator>( new ObjectFactory() { @Override public ValueIterator create() { return new ValueIterator(); } @Override public void initialize(final ValueIterator obj) { obj.cursor.index = 0; obj.size = ObjectHeapPriorityQueue.this.size(); obj.buffer = ObjectHeapPriorityQueue.this.buffer; } @Override public void reset(final ValueIterator obj) { // for GC sake obj.buffer = null; } }); } /** * Create with default sizing strategy and initial capacity for storing * {@value #DEFAULT_CAPACITY} elements. * * @see BoundedProportionalArraySizingStrategy */ public ObjectHeapPriorityQueue( final Comparator comp ) { this(comp, ObjectHeapPriorityQueue.DEFAULT_CAPACITY); } /** * Create with an initial capacity, * using the Comparable natural ordering */ public ObjectHeapPriorityQueue(final int initialCapacity) { this(null, initialCapacity, new BoundedProportionalArraySizingStrategy()); } /** * Create with a given initial capacity, using a * Comparator for ordering. * * @see BoundedProportionalArraySizingStrategy */ public ObjectHeapPriorityQueue( final Comparator comp, final int initialCapacity) { this(comp, initialCapacity, new BoundedProportionalArraySizingStrategy()); } /** * {@inheritDoc} *

Note : The comparison criteria for * identity test is based on * * {@link Comparable} compareTo() if no * * custom comparator is given, else it uses the {@link #comparator()} criteria. */ @Override public int removeAllOccurrences(final KType e1) { this.currentOccurenceToBeRemoved = e1; return removeAll(this.removeAllOccurencesPredicate); } /** * {@inheritDoc} */ @Override public int removeAll(final ObjectPredicate predicate) { //remove by position int deleted = 0; final KType[] buffer = this.buffer; int elementsCount = this.elementsCount; //1-based index int pos = 1; try { while (pos <= elementsCount) { //delete it if (predicate.apply(buffer[pos])) { //put the last element at position pos, like in deleteIndex() buffer[pos] = buffer[elementsCount]; //for GC buffer[elementsCount] = (null); //Diminish size elementsCount--; deleted++; } //end if to delete else { pos++; } } //end while } finally { this.elementsCount = elementsCount; //reestablish heap updatePriorities(); } return deleted; } /** * {@inheritDoc} */ @Override public void clear() { //1-based indexing ObjectArrays.blankArray(this.buffer, 1, this.elementsCount + 1); this.elementsCount = 0; } /** * An iterator implementation for {@link HeapPriorityQueue#iterator}. * Holds a ObjectCursor cursor returning (value, index) = (KType value, index the position in heap) */ public final class ValueIterator extends AbstractIterator> { public final ObjectCursor cursor; private KType[] buffer; private int size; public ValueIterator() { this.cursor = new ObjectCursor(); //index 0 is not used in Priority queue this.cursor.index = 0; this.size = ObjectHeapPriorityQueue.this.size(); this.buffer = ObjectHeapPriorityQueue.this.buffer; } @Override protected ObjectCursor fetch() { //priority is 1-based index if (this.cursor.index == this.size) { return done(); } this.cursor.value = this.buffer[++this.cursor.index]; return this.cursor; } } /** * {@inheritDoc} */ @Override public ValueIterator iterator() { //return new ValueIterator(buffer, size()); return this.valueIteratorPool.borrow(); } /** * {@inheritDoc} *

Note : The comparison criteria for * identity test is based on * * {@link Comparable} compareTo() if no * * custom comparator is given, else it uses the {@link #comparator()} criteria. */ @Override public boolean contains(final KType element) { //1-based index final int size = this.elementsCount; final KType[] buff = this.buffer; if (this.comparator == null) { for (int i = 1; i <= size; i++) { if ((((Comparable) element).compareTo(buff[i]) == 0)) { return true; } } //end for } else { final Comparator comp = this.comparator; for (int i = 1; i <= size; i++) { if (comp.compare(element, buff[i]) == 0) { return true; } } //end for } return false; } /** * {@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 KType[] buff = this.buffer; final int size = this.elementsCount; for (int i = 1; i <= size; i++) { procedure.apply(buff[i]); } return procedure; } /** * {@inheritDoc} */ @Override public > T forEach(final T predicate) { final KType[] buff = this.buffer; final int size = this.elementsCount; for (int i = 1; i <= size; i++) { if (!predicate.apply(buff[i])) { break; } } return predicate; } /** * Insert a KType into the queue. * cost: O(log(N)) for a N sized queue */ @Override public void add(final KType element) { ensureBufferSpace(1); //add at the end this.elementsCount++; this.buffer[this.elementsCount] = element; //swim last element swim(this.elementsCount); } /** * {@inheritDoc} * cost: O(1) */ @Override public KType top() { KType elem = this.defaultValue; if (this.elementsCount > 0) { elem = this.buffer[1]; } return elem; } /** * {@inheritDoc} * cost: O(log(N)) for a N sized queue */ @Override public KType popTop() { KType elem = this.defaultValue; if (this.elementsCount > 0) { elem = this.buffer[1]; if (this.elementsCount == 1) { //for GC this.buffer[1] = (null); //diminish size this.elementsCount = 0; } else { //at least 2 elements //put the last element in first position this.buffer[1] = this.buffer[this.elementsCount]; //for GC this.buffer[this.elementsCount] = (null); //diminish size this.elementsCount--; //percolate down the first element sink(1); } } return elem; } /** * Adds all elements from another container. * cost: O(N*log(N)) for N elements */ public int addAll(final ObjectContainer container) { return addAll((Iterable>) container); } /** * Adds all elements from another iterable. * cost: O(N*log(N)) for N elements */ public int addAll(final Iterable> iterable) { int size = 0; final KType[] buff = this.buffer; int count = this.elementsCount; for (final ObjectCursor cursor : iterable) { ensureBufferSpace(1); count++; buff[count] = cursor.value; size++; } this.elementsCount = count; //restore heap updatePriorities(); return size; } /** * {@inheritDoc} */ @Override public int hashCode() { int h = 1; final int max = this.elementsCount; final KType[] buff = this.buffer; //1-based index for (int i = 1; i <= max; i++) { h = 31 * h + Internals.rehash(buff[i]); } return h; } /** * {@inheritDoc} * cost: O(n*log(N)) */ @Override 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); } } } /** * {@inheritDoc} * cost: O(log(N)) */ @Override public void updateTopPriority() { //only attempt to sink if there is at least 2 elements.... if (this.elementsCount > 1) { sink(1); } } /** * Clone this object. The returned clone will use the same resizing strategy and comparator. * It also realizes a trim-to- this.size() in the process. */ @Override public ObjectHeapPriorityQueue clone() { //real constructor call final ObjectHeapPriorityQueue cloned = new ObjectHeapPriorityQueue(this.comparator, this.size(), this.resizer); cloned.addAll(this); cloned.defaultValue = this.defaultValue; return cloned; } /** * this instance and obj can only be equal to this 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 /* */ @SuppressWarnings("unchecked") /* */ public boolean equals(final Object obj) { if (obj != null) { if (obj == this) { return true; } //we can only compare both ObjectHeapPriorityQueue, //that has the same comparison function reference if (obj instanceof ObjectHeapPriorityQueue) { final ObjectHeapPriorityQueue other = (ObjectHeapPriorityQueue) obj; if (other.size() != this.size()) { return false; } final int size = this.elementsCount; final KType[] buffer = this.buffer; final KType[] otherbuffer = other.buffer; //both heaps must have the same comparison criteria if (this.comparator == null && other.comparator == null) { for (int i = 1; i <= size; i++) { if (!(((Comparable) buffer[i]).compareTo(otherbuffer[i]) == 0)) { return false; } } return true; } else if (this.comparator != null && this.comparator.equals(other.comparator)) { final Comparator comp = this.comparator; for (int i = 1; i <= size; i++) { if (comp.compare(buffer[i], otherbuffer[i]) != 0) { return false; } } return true; } } //end if ObjectHeapPriorityQueue } return false; } /** * Ensures the internal buffer has enough free slots to store * expectedAdditions. Increases internal buffer size if needed. */ protected void ensureBufferSpace(final int expectedAdditions) { final int bufferLen = (this.buffer == null ? 0 : this.buffer.length - 1); if (this.elementsCount > bufferLen - expectedAdditions) { final int newSize = this.resizer.grow(bufferLen, this.elementsCount, expectedAdditions + 1); assert newSize >= this.elementsCount + expectedAdditions : "Resizer failed to" + " return sensible new size: " + newSize + " <= " + (this.elementsCount + expectedAdditions); final KType[] newBuffer = (Internals.newArray(newSize)); if (bufferLen > 0) { System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length); } this.buffer = newBuffer; } } /** * {@inheritDoc} */ @Override public KType[] toArray(final KType[] target) { //copy from index 1 System.arraycopy(this.buffer, 1, target, 0, this.elementsCount); return target; } /** * Get the custom comparator used for comparing elements * @return null if no custom comparator was set, i.e natural ordering * of KTypes is used instead * , which means objects in this case must be {@link Comparable}. * */ public Comparator comparator() { return this.comparator; } /** * Sink function for Comparable elements * @param k */ private void sinkComparable(int k) { final int N = this.elementsCount; final KType[] buffer = this.buffer; KType tmp; int child; while ((k << 1) <= N) { //get the child of k child = k << 1; if (child < N && (((Comparable) buffer[child]).compareTo(buffer[child + 1]) > 0)) { child++; } if (!(((Comparable) buffer[k]).compareTo(buffer[child]) > 0)) { break; } //swap k and child tmp = buffer[k]; buffer[k] = buffer[child]; buffer[child] = tmp; k = child; } //end while } /** * Sink function for ObjectComparator elements * @param k */ private void sinkComparator(int k) { final int N = this.elementsCount; final KType[] buffer = this.buffer; KType tmp; int child; final Comparator 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; k = child; } //end while } /** * Swim function for Comparable elements * @param k */ private void swimComparable(int k) { KType tmp; int parent; final KType[] buffer = this.buffer; while (k > 1 && (((Comparable) buffer[k >> 1]).compareTo(buffer[k]) > 0)) { //swap k and its parent parent = k >> 1; tmp = buffer[k]; buffer[k] = buffer[parent]; buffer[parent] = tmp; k = parent; } } /** * Swim function for Comparator elements * @param k */ private void swimComparator(int k) { KType tmp; int parent; final KType[] buffer = this.buffer; final Comparator comp = this.comparator; while (k > 1 && comp.compare(buffer[k >> 1], buffer[k]) > 0) { //swap k and its parent parent = k >> 1; tmp = buffer[k]; buffer[k] = buffer[parent]; buffer[parent] = tmp; 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); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy