package de.spieleck.util;
/* Please see the license information in the header below. */
/*
NGramJ - n-gram based text classification
Copyright (C) 2001 Frank S. Nestel (frank at spieleck.de)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program (lesser.txt); if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
import java.util.Comparator;
/** A PriorityQueue maintains a partial ordering of its elements such that the
least element can always be found in constant time.
<P>
This is achieved by a heap implementation, therefore
Put()'s and pop()'s require log(size) time. Note that this heap is
realized by linear insertion and not by "bubbling".
<P>
This class can either be directly used by passing a
<code>java.util.Comparator</code>
object to the constructor, or by subclassing and overriding the
<code>lessThan()</code> method.
<P>
<B>XXX</B> This is an lazy implementation which spoils the very first
entry in the heap!
<P>
<B>Caution:</B>This class is unsynchronized and therefore
needs external synchronization in an multithreading environment.
*/
@SuppressWarnings("unchecked")
public class PriorityQueue
{
protected int size;
protected Object[] heap;
protected Comparator myComp;
public PriorityQueue(int initialSize, Comparator comp)
{
myComp = comp;
initialize(initialSize);
}
/** Determines the ordering of objects in this priority queue.
* Subclasses can override this method.
*/
protected boolean lessThan(Object a, Object b)
{
return myComp.compare(a,b) < 0;
}
public void setComparator(Comparator comp)
{
myComp = comp;
resort();
}
/** Subclass constructors must call this. */
protected final void initialize(int initialSize)
{
size = 0;
int heapSize = initialSize;
heap = new Object[heapSize];
}
/** Adds an Object to a PriorityQueue in log(size) time.
Unless resize occurs ...
*/
public final void put(Object element)
{
size++;
if ( size >= heap.length )
{
Object[] newHeap = new Object[2*heap.length];
for (int i = 1; i < size; i++ )
{
newHeap[i] = heap[i];
heap[i] = null; // help GC() ?!
}
heap = newHeap;
}
heap[size] = element;
upHeap();
}
/**
* Replace the topmost element.
*/
public final void setTop(Object element)
{
heap[1] = element;
adjustTop();
}
/** Returns the least element of the PriorityQueue in constant time. */
public final Object top()
{
if (size > 0)
return heap[1];
else
return null;
}
/** Removes and returns the least element of the PriorityQueue in log(size)
time. */
public final Object pop()
{
if (size > 0)
{
Object result = heap[1]; // save first value
heap[1] = heap[size]; // move last to first
heap[size] = null; // permit GC of objects
size--;
downHeap(1); // adjust heap
return result;
}
else
return null;
}
/** Should be called when the Object at top changes values. Still log(n)
* worst case, but it's at least twice as fast to <pre>
* { pq.top().change(); pq.adjustTop(); }
* </pre> instead of <pre>
* { o = pq.pop(); o.change(); pq.push(o); }
* </pre>
*/
public final void adjustTop()
{
downHeap(1);
}
/** Returns the number of elements currently stored in the PriorityQueue. */
public final int getSize()
{
return size;
}
/** Returns current capacity */
public final int getCapacity()
{
return heap.length;
}
/** Removes all entries from the PriorityQueue. */
public final void clear()
{
for (int i = 1; i < size; i++)
heap[i] = null;
size = 0;
}
/** Rearrange the heap, this is supposed to be
O(n*log(n)) but better than nothing
*/
public void resort()
{
int i = size / 2;
while ( i > 1 )
{
downHeap(i);
i--;
}
}
/**
* readjust last node in the heap to maintain heap condition.
*/
protected final void upHeap()
{
int i = size;
Object node = heap[i]; // save bottom node
int j = i >>> 1;
while (j > 0 && lessThan(node, heap[j]))
{
heap[i] = heap[j]; // shift parents down
i = j;
j = j >>> 1;
}
heap[i] = node; // install saved node
}
/**
* readjust top node in the heap to maintain heap condition.
*/
protected final void downHeap(int top)
{
int i = top;
Object node = heap[i]; // save top node
int j = i << 1; // find smaller child
int k = j + 1;
if (k <= size && lessThan(heap[k], heap[j]))
j = k;
while (j <= size && lessThan(heap[j], node))
{
heap[i] = heap[j]; // sift up child
i = j;
j = i << 1;
k = j + 1;
if (k <= size && lessThan(heap[k], heap[j]))
j = k;
}
heap[i] = node; // place saved node
}
}