/** * */ 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); } }