com.carrotsearch.hppcrt.heaps.DoubleHeapPriorityQueue Maven / Gradle / Ivy
Show all versions of hppcrt Show documentation
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 double
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()} .
* @author Vincent Sonnier
*/
@javax.annotation.Generated(date = "2015-02-27T19:21:03+0100", value = "HPPC-RT generated from: DoubleHeapPriorityQueue.java")
public class DoubleHeapPriorityQueue extends AbstractDoubleCollection
implements DoublePriorityQueue, 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 priority queue iteration: iterate buffer[i] for i in [1; size()] (included) but is out-of-order w.r.t {@link #popTop()}
*
*/
public double[] buffer;
/**
* Number of elements in the queue.
*/
protected int elementsCount;
/**
* Defines the Comparator ordering of the queue,
* If null, natural ordering is used.
*/
protected DoubleComparator 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
*/
private double currentOccurenceToBeRemoved;
/**
* Internal predicate for removeAll
*/
private final DoublePredicate removeAllOccurencesPredicate = new DoublePredicate() {
@Override
public final boolean apply(final double value) {
if (DoubleHeapPriorityQueue.this.comparator == null) {
if ((Double.doubleToLongBits(value) == Double.doubleToLongBits(DoubleHeapPriorityQueue.this.currentOccurenceToBeRemoved))) {
return true;
}
}
else {
if (DoubleHeapPriorityQueue.this.comparator.compare(value, DoubleHeapPriorityQueue.this.currentOccurenceToBeRemoved) == 0) {
return true;
}
}
return false;
}
};
/**
* Create with a Comparator, an initial capacity, and a custom buffer resizing strategy.
*/
public DoubleHeapPriorityQueue( DoubleComparator 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 = (new double[internalSize + 1]);
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 = DoubleHeapPriorityQueue.this.size();
obj.buffer = DoubleHeapPriorityQueue.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 DoubleHeapPriorityQueue( DoubleComparator comp
)
{
this(comp, DoubleHeapPriorityQueue.DEFAULT_CAPACITY);
}
/**
* Create with an initial capacity,
* using the natural ordering of double
s
*/
public DoubleHeapPriorityQueue(final int initialCapacity)
{
this(null, initialCapacity, new BoundedProportionalArraySizingStrategy());
}
/**
* Create with a given initial capacity, using a
* Comparator for ordering.
*
* @see BoundedProportionalArraySizingStrategy
*/
public DoubleHeapPriorityQueue( DoubleComparator comp,
final int initialCapacity)
{
this(comp, initialCapacity, new BoundedProportionalArraySizingStrategy());
}
/**
* {@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 int removeAllOccurrences(final double e1)
{
this.currentOccurenceToBeRemoved = e1;
return removeAll(this.removeAllOccurencesPredicate);
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(final DoublePredicate predicate)
{
//remove by position
int deleted = 0;
final double[] 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 HeapPriorityQueue#iterator}.
* Holds a DoubleCursor cursor returning (value, index) = (double value, index the position in heap)
*/
public final class ValueIterator extends AbstractIterator
{
public final DoubleCursor cursor;
private double[] buffer;
private int size;
public ValueIterator()
{
this.cursor = new DoubleCursor();
//index 0 is not used in Priority queue
this.cursor.index = 0;
this.size = DoubleHeapPriorityQueue.this.size();
this.buffer = DoubleHeapPriorityQueue.this.buffer;
}
@Override
protected DoubleCursor 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
* * natural ordering if no
* * custom comparator is given, else it uses the {@link #comparator()} criteria.
*/
@Override
public boolean contains(final double element)
{
//1-based index
final int size = this.elementsCount;
final double[] buff = this.buffer;
if (this.comparator == null) {
for (int i = 1; i <= size; i++)
{
if ((Double.doubleToLongBits(element) == Double.doubleToLongBits(buff[i])))
{
return true;
}
} //end for
}
else {
DoubleComparator 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 double[] 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 double[] 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 double into the queue.
* cost: O(log(N)) for a N sized queue
*/
@Override
public void add(final double 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 double top()
{
double 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 double popTop()
{
double 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 DoubleContainer container)
{
return addAll((Iterable extends DoubleCursor>) container);
}
/**
* Adds all elements from another iterable.
* cost: O(N*log(N)) for N elements
*/
public int addAll(final Iterable extends DoubleCursor> iterable)
{
int size = 0;
final double[] buff = this.buffer;
int count = this.elementsCount;
for (final DoubleCursor 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 double[] 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 DoubleHeapPriorityQueue clone()
{
//real constructor call
final DoubleHeapPriorityQueue cloned = new DoubleHeapPriorityQueue(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
/* */
public boolean equals(final Object obj)
{
if (obj != null)
{
if (obj == this) {
return true;
}
//we can only compare both DoubleHeapPriorityQueue,
//that has the same comparison function reference
if (obj instanceof DoubleHeapPriorityQueue)
{
final DoubleHeapPriorityQueue other = (DoubleHeapPriorityQueue) obj;
if (other.size() != this.size()) {
return false;
}
final int size = this.elementsCount;
final double[] buffer = this.buffer;
final double[] 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 (!(Double.doubleToLongBits(buffer[i]) == Double.doubleToLongBits(otherbuffer[i])))
{
return false;
}
}
return true;
}
else if (this.comparator != null && this.comparator.equals(other.comparator)) {
DoubleComparator comp = this.comparator;
for (int i = 1; i <= size; i++)
{
if (comp.compare(buffer[i], otherbuffer[i]) != 0)
{
return false;
}
}
return true;
}
} //end if DoubleHeapPriorityQueue
}
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 double[] newBuffer = (new double[newSize]);
if (bufferLen > 0)
{
System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length);
}
this.buffer = newBuffer;
}
}
/**
* {@inheritDoc}
*/
@Override
public double[] toArray(final double[] 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 double
s is used instead
* */
public DoubleComparator
comparator() {
return this.comparator;
}
/**
* Sink function for Comparable elements
* @param k
*/
private void sinkComparable(int k)
{
final int N = this.elementsCount;
final double[] buffer = this.buffer;
double tmp;
int child;
while ((k << 1) <= N)
{
//get the child of k
child = k << 1;
if (child < N && (Double.compare(buffer[child] , buffer[child + 1]) > 0))
{
child++;
}
if (!(Double.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
}
/**
* Sink function for DoubleComparator elements
* @param k
*/
private void sinkComparator(int k)
{
final int N = this.elementsCount;
final double[] buffer = this.buffer;
double tmp;
int child;
DoubleComparator 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)
{
double tmp;
int parent;
final double[] buffer = this.buffer;
while (k > 1 && (Double.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;
}
}
/**
* Swim function for Comparator elements
* @param k
*/
private void swimComparator(int k)
{
double tmp;
int parent;
final double[] buffer = this.buffer;
DoubleComparator 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);
}
}
}