com.carrotsearch.hppcrt.heaps.LongHeapPriorityQueue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hppcrt Show documentation
Show all versions of hppcrt Show documentation
High Performance Primitive Collections Realtime
(fork of HPPC from Carrotsearch)
Fundamental data structures (maps, sets, lists, queues, heaps, sorts) generated for
combinations of object and primitive types to conserve JVM memory and speed
up execution. The Realtime fork intends to extend the existing collections, by tweaking to remove any dynamic allocations at runtime,
and to obtain low variance execution times whatever the input nature.
The newest version!
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, min-priority queue of long
s.
* 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 natural ordering
* * or by a custom comparator provided in constructors,
* see {@link #comparator()} .
*/
@javax.annotation.Generated(
date = "2017-07-11T19:16:22+0200",
value = "KTypeHeapPriorityQueue.java")
public class LongHeapPriorityQueue extends AbstractLongCollection
implements LongPriorityQueue, Cloneable
{
/**
* Internal array for storing the priority queue.
*
* Direct priority queue iteration: iterate buffer[i] for i in [1; size()] (included) but is out-of-order w.r.t {@link #popTop()}
*
*/
public long []
buffer;
/**
* Number of elements in the queue.
*/
protected int elementsCount;
/**
* Defines the Comparator ordering of the queue,
* If null, natural ordering is used.
*/
protected LongComparator comparator;
/**
* Buffer resizing strategy.
*/
protected final ArraySizingStrategy resizer;
/**
* internal pool of ValueIterator (must be created in constructor)
*/
protected final IteratorPool valueIteratorPool;
/**
* The current value set for removeAll
*/
protected long currentOccurenceToBeRemoved;
/**
* Internal predicate for removeAll
*/
protected LongPredicate removeAllOccurencesPredicate = new LongPredicate() {
@Override
public final boolean apply(final long value) {
if (((value) == (LongHeapPriorityQueue.this.currentOccurenceToBeRemoved))) {
return true;
}
return false;
}
};
/**
* Default value returned when specified
* in methods.
* @see #top()
*/
protected long defaultValue;
/**
* Create with a Comparator, an initial capacity, and a custom buffer resizing strategy.
*/
public LongHeapPriorityQueue( LongComparator comp,
final int initialCapacity, final ArraySizingStrategy resizer) {
this.comparator = comp;
assert resizer != null;
this.resizer = resizer;
//1-based index buffer, assure allocation
ensureBufferSpace(Math.max(Containers.DEFAULT_EXPECTED_ELEMENTS, initialCapacity));
this.valueIteratorPool = new IteratorPool(new ObjectFactory() {
@Override
public ValueIterator create() {
return new ValueIterator();
}
@Override
public void initialize(final ValueIterator obj) {
obj.cursor.index = 0;
obj.size = LongHeapPriorityQueue.this.size();
obj.buffer = ((LongHeapPriorityQueue.this.buffer));
}
@Override
public void reset(final ValueIterator obj) {
// for GC sake
obj.buffer = null;
}
});
}
/**
* Create with default sizing strategy and initial capacity
* ({@link Containers#DEFAULT_EXPECTED_ELEMENTS})
* using a specific Comparator.
*
* @see BoundedProportionalArraySizingStrategy
*/
public LongHeapPriorityQueue( LongComparator 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 long
s.
*/
public LongHeapPriorityQueue() {
this(null, Containers.DEFAULT_EXPECTED_ELEMENTS);
}
/**
* Create with an initial capacity,
* using the natural ordering of long
s
*/
public LongHeapPriorityQueue(final int initialCapacity) {
this(null, initialCapacity, new BoundedProportionalArraySizingStrategy());
}
/**
* Create with a given initial capacity, using a
* Comparator for ordering.
*
* @see BoundedProportionalArraySizingStrategy
*/
public LongHeapPriorityQueue( LongComparator comp,
final int initialCapacity)
{
this(comp, initialCapacity, new BoundedProportionalArraySizingStrategy());
}
/**
* Creates a new heap from elements of another container.
*/
public LongHeapPriorityQueue(final LongContainer container) {
this(container.size());
addAll(container);
}
/**
* Create a heap from elements of another container (constructor shortcut)
*/
public static/* */
LongHeapPriorityQueue from(final LongContainer container) {
return new LongHeapPriorityQueue(container);
}
/**
* Create a heap from a variable number of arguments or an array of
* long
.
*/
public static/* */
LongHeapPriorityQueue from(final long... elements) {
final LongHeapPriorityQueue heap = new LongHeapPriorityQueue(elements.length);
for (final long elem : elements) {
heap.add(elem);
}
return heap;
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(final long e1) {
this.currentOccurenceToBeRemoved = e1;
return removeAll(this.removeAllOccurencesPredicate);
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(final LongPredicate predicate) {
//remove by position
int deleted = 0;
final long[] 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
//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() {
this.elementsCount = 0;
}
/**
* An iterator implementation for {@link LongHeapPriorityQueue#iterator}.
* Holds a LongCursor returning (value, index) = (long value, index the position in heap {@link LongHeapPriorityQueue#buffer}.)
*/
public final class ValueIterator extends AbstractIterator
{
public final LongCursor cursor;
private long[] buffer;
private int size;
public ValueIterator() {
this.cursor = new LongCursor();
//index 0 is not used in Priority queue
this.cursor.index = 0;
this.size = LongHeapPriorityQueue.this.size();
this.buffer = ((LongHeapPriorityQueue.this.buffer));
}
@Override
protected LongCursor 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}
*/
@Override
public boolean contains(final long element) {
//1-based index
final int size = this.elementsCount;
final long[] buff = ((this.buffer));
for (int i = 1; i <= size; i++) {
if (((element) == (buff[i]))) {
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 long[] 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 long[] 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 long into the queue.
* cost: O(log(N)) for a N sized queue
*/
@Override
public void add(final long 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 long top() {
long 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 long popTop() {
long elem = this.defaultValue;
if (this.elementsCount > 0) {
elem = ((this.buffer[1]));
if (this.elementsCount == 1) {
//for GC
//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
//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 LongContainer container) {
return addAll((Iterable extends LongCursor>) container);
}
/**
* Adds all elements from another iterable.
* cost: O(N*log(N)) for N elements
*/
public int addAll(final Iterable extends LongCursor> iterable) {
int size = 0;
final long[] buff = ((this.buffer));
int count = this.elementsCount;
for (final LongCursor 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 long[] buff = ((this.buffer));
//1-based index
for (int i = 1; i <= max; i++) {
h = 31 * h + BitMixer.mix(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.
*/
@Override
public LongHeapPriorityQueue clone() {
//real constructor call, of a place holder
final LongHeapPriorityQueue cloned = new LongHeapPriorityQueue(this.comparator,
Containers.DEFAULT_EXPECTED_ELEMENTS, this.resizer);
//clone raw buffers
cloned.buffer = this.buffer.clone();
cloned.defaultValue = this.defaultValue;
cloned.elementsCount = this.elementsCount;
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 heap elements are compared with {@link #equals(Object)} iterating their {@link #buffer}.
*/
@Override
/* */
public boolean equals(final Object obj) {
if (obj != null) {
if (obj == this) {
return true;
}
//we can only compare both LongHeapPriorityQueue and not subclasses between themselves
//that has the same comparison function reference
if (obj.getClass() != this.getClass()) {
return false;
}
final LongHeapPriorityQueue other = (LongHeapPriorityQueue) 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;
}
final ValueIterator it = this.iterator();
final ValueIterator itOther = other.iterator();
while (it.hasNext()) {
final long myVal = it.next().value;
final long otherVal = itOther.next().value;
if (!((myVal) == (otherVal))) {
//recycle
it.release();
itOther.release();
return false;
}
} //end while
itOther.release();
return true;
}
return false;
}
/**
* Ensures the internal buffer has enough free slots to store
* expectedAdditions
. Increases internal buffer size if needed.
*/
@SuppressWarnings("boxing")
protected void ensureBufferSpace(final int expectedAdditions) {
final int bufferLen = this.buffer == null ? 0 : this.buffer.length;
//element of index 0 is not used
if (this.elementsCount + 1 > bufferLen - expectedAdditions) {
int newSize = this.resizer.grow(bufferLen, this.elementsCount, expectedAdditions);
//first allocation, reserve an additional slot because index 0 is not used
if (this.buffer == null) {
newSize++;
}
try {
final long[] newBuffer = (new long[(newSize)]);
if (bufferLen > 0) {
System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length);
}
this.buffer = newBuffer;
} catch (final OutOfMemoryError e) {
throw new BufferAllocationException(
"Not enough memory to allocate buffers to grow from %d -> %d elements",
e,
bufferLen,
newSize);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public long[] toArray(final long[] 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 long
s is used instead
* */
public LongComparator
comparator() {
return this.comparator;
}
/**
* Returns the "default value" value used
* in methods returning "default value"
*/
@Override
public long getDefaultValue()
{
return this.defaultValue;
}
/**
* Set the "default value" value to be used
* in methods returning "default value"
*/
@Override
public void setDefaultValue(final long defaultValue)
{
this.defaultValue = defaultValue;
}
/**
* Sink function for Comparable elements
*
* @param k
*/
private void sinkComparable(int k) {
final int N = this.elementsCount;
final long[] buffer = ((this.buffer));
long tmp;
int child;
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;
k = child;
} //end while
}
/**
* Sink function for LongComparator elements
*
* @param k
*/
private void sinkComparator(int k) {
final int N = this.elementsCount;
final long[] buffer = ((this.buffer));
long tmp;
int child;
LongComparator 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) {
long tmp;
int parent;
final long[] buffer = ((this.buffer));
while (k > 1 && ((buffer[k >> 1]) > (buffer[k]))) {
//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) {
long tmp;
int parent;
final long[] buffer = ((this.buffer));
LongComparator 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);
}
}
}