/**
*
*/
package net.varkhan.base.containers.queue;
import net.varkhan.base.containers.Iterator;
import java.util.Arrays;
import java.util.NoSuchElementException;
/**
* <b>A heap-based unbounded priority queue containing {@code int}s.</b>
* <p/>
* This class uses an extensible heap to provide the semantics of a priority
* queue on {@code int}s, using either ascending or descending order.
* <p/>
* When the size of the queue equals the current size of the heap, the heap is
* extended. It does not shrink when elements are removed, but can be made to
* fit the number of elements in the queue by calling the {@link #pack()} method.
* <p/>
*
* @author varkhan
* @date Mar 13, 2009
* @time 10:26:01 PM
*/
public class OpenHeapIntQueue implements IntQueue {
/**
* The heap array growth factor
*/
private final float growthfactor;
/**
* The heap array.
*/
private int[] heap;
/**
* The number of elements in this queue.
*/
private int size=0;
/**
* The starting point of the queue in the array.
*/
private int base=0;
/**
* A flag indicating whether to sort in descending order
*/
private final boolean desc;
/**********************************************************************************
** Constructors
**/
/**
* Creates a new empty queue with a given capacity and comparator.
*
* @param capacity the initial capacity of this queue.
* @param growthfactor the multiplicative resizing factor for the queue storage array
* @param desc if {@literal true}, change the semantics of {@link #poll()} and {@link #peek()}
* to return the highest value instead of the lowest
*/
public OpenHeapIntQueue(int capacity, float growthfactor, boolean desc) {
if(growthfactor<1.0f) growthfactor=1.0f;
this.growthfactor=growthfactor;
this.heap=new int[capacity];
this.desc=desc;
}
/**
* Creates a new empty queue with a given capacity and comparator.
*
* @param capacity the initial capacity of this queue.
* @param desc if {@literal true}, change the semantics of {@link #poll()} and {@link #peek()}
* to return the highest value instead of the lowest
*/
public OpenHeapIntQueue(int capacity, boolean desc) {
this(capacity, 1.5f, desc);
}
/**
* Creates a new empty queue with a given capacity and using the natural order.
*
* @param capacity the initial capacity of this queue.
*/
public OpenHeapIntQueue(int capacity) {
this(capacity, 1.5f, false);
}
/**
* Creates a new empty queue with a given comparator.
*
* @param desc if {@literal true}, change the semantics of {@link #poll()} and {@link #peek()}
* to return the highest value instead of the lowest
*/
public OpenHeapIntQueue(boolean desc) {
this(11, 1.5f, desc);
}
/**
* Creates a new empty queue with a given capacity and using the natural order.
*/
public OpenHeapIntQueue() {
this(11, 1.5f, false);
}
/**********************************************************************************
** Global information accessors
**/
/**
* Return the queue size
*
* @return the number of objects in the queue
*/
public long size() {
return size;
}
/**
* Indicates whether this container is empty.
*
* @return {@literal true} if this container contains no entry,
* {@literal false} otherwise
*/
public boolean isEmpty() {
return size<=0;
}
/**
* Indicates whether this queue is sorted in descending order instead of ascending order
*
* @return {@literal true} if {@link #poll()} and {@link #peek()}
* return the highest value in the queue instead of the lowest
*/
public boolean descending() {
return desc;
}
/**
* Removes all objects from the queue
*/
public final void clear() {
size=0;
base=0;
}
/**
* Resize the internal storage array(s) so that this object takes the minimal space possible
*/
public void pack() {
if(heap.length>size) {
heap=Arrays.copyOfRange(heap, base, base+size);
base=0;
}
}
/**********************************************************************************
** Queue mecanism
**/
/**
* Adds an object on the queue.
*
* @param obj the object to add
*
* @return {@literal true} if the object was added, {@literal false} if
* the object could not be added (for instance, because a limit on the
* queue content has been reached)
*/
public boolean add(Integer obj) {
return add((int) obj);
}
/**
* Adds an object on the queue.
*
* @param objVal the object to add
*
* @return {@literal true} if the object was added, {@literal false} if
* the object could not be added (for instance, because a limit on the
* queue content has been reached)
*/
public boolean add(int objVal) {
int min=base;
int max=base+size-1;
if(desc) {
// Sort in ascending order
while(min<=max) {
int med=(min+max)>>>1;
int medVal=heap[med];
if(medVal>objVal) min=med+1;
else if(medVal<objVal) max=med-1;
else {
if(base>0) {
System.arraycopy(heap, base, heap, base-1, med-base);
base--;
heap[med-1]=objVal;
size++;
}
else {
if(size>=heap.length) {
heap=Arrays.copyOf(heap, (int) ((size+1)*growthfactor));
}
System.arraycopy(heap, med, heap, med+1, size-med);
heap[med]=objVal;
size++;
}
return true;
}
}
}
else {
// Sort in descending order
while(min<=max) {
int med=(min+max)>>>1;
long medVal=heap[med];
if(medVal<objVal) min=med+1;
else if(medVal>objVal) max=med-1;
else {
if(base>0) {
System.arraycopy(heap, base, heap, base-1, med-base);
base--;
heap[med-1]=objVal;
size++;
}
else {
if(size>=heap.length) {
heap=Arrays.copyOf(heap, (int) ((size+1)*growthfactor));
}
System.arraycopy(heap, med, heap, med+1, size-med);
heap[med]=objVal;
size++;
}
return true;
}
}
}
if(base>0) {
System.arraycopy(heap, base, heap, base-1, min-base);
base--;
heap[min-1]=objVal;
size++;
}
else {
if(size>=heap.length) {
heap=Arrays.copyOf(heap, (int) ((size+1)*growthfactor));
}
System.arraycopy(heap, min, heap, min+1, size-min);
heap[min]=objVal;
size++;
}
return true;
}
/**
* Removes and return the lowest value on the queue
*
* @return the lowest value on the queue
*/
public Integer poll() {
if(size==0) throw new NoSuchElementException();
final int obj=heap[base];
base++;
size--;
return obj;
}
/**
* Removes and return the lowest value on the queue
*
* @return the lowest value on the queue
*/
public int dequeueInt() {
if(size==0) throw new NoSuchElementException();
final int obj=heap[base];
base++;
size--;
return obj;
}
/**
* Returns, without removing it, the lowest value on the queue
*
* @return the lowest value on the queue
*/
public Integer peek() {
if(size==0) throw new NoSuchElementException();
return heap[base];
}
/**
* Returns, without removing it, the lowest value on the queue
*
* @return the lowest value on the queue
*/
public int getInt() {
if(size==0) throw new NoSuchElementException();
return heap[base];
}
/**********************************************************************************
** Iterator operations
**/
/**
* Returns an element at a given position
*
* @param pos the position in the queue
*
* @return the element at position {@code pos}
*/
public Integer get(int pos) {
if(pos>=size) throw new ArrayIndexOutOfBoundsException(pos);
return heap[base+pos];
}
/**
* Returns an element at a given position
*
* @param pos the position in the queue
*
* @return the element at position {@code pos}
*/
public int getInt(int pos) {
if(pos>=size) throw new ArrayIndexOutOfBoundsException(pos);
return heap[base+pos];
}
/**
* Returns an iterator over the elements of the queue
*
* @return an Iterator.
*/
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
private int pos=0;
public boolean hasNext() {
return pos<size;
}
public Integer next() {
return heap[base+pos++];
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Iterate over each element of the queue, and pass it as argument to a
* visitor's {@link Visitor#invoke(Object, Object)} method, until this method returns
* a negative count.
*
*
* @param vis the visitor
* @param par the control parameter
*
* @return the sum of all positive return values from the visitor
*/
public <Par> long visit(Visitor<Integer,Par> vis, Par par) {
int pos=0;
long c=0;
while(pos<size) {
int obj;
if(base+pos<heap.length) obj=heap[base+(pos++)];
else obj=heap[base+(pos++)-heap.length];
long r=vis.invoke(obj, par);
if(r<0) return c;
c+=r;
}
return c;
}
/**
* Iterate over each element of the queue, and pass it as argument to a
* visitor's {@link Visitor#invoke(Object, Object)} method, until this method returns
* a negative count.
*
*
* @param vis the visitor
* @param par the control parameter
*
* @return the sum of all positive return values from the visitor
*/
public <Par> long visit(IntVisitor<Par> vis, Par par) {
int pos=0;
long c=0;
while(pos<size) {
int obj;
if(base+pos<heap.length) obj=heap[base+(pos++)];
else obj=heap[base+(pos++)-heap.length];
long r=vis.invoke(obj, par);
if(r<0) return c;
c+=r;
}
return c;
}
/**
* Returns a string representation of the queue
*
* @return the string representation of the array of values in the queue
*/
public String toString() {
return net.varkhan.base.containers.array.IntArrays.toString(heap);
}
}