package cc.mallet.util.search;
/**
* Created by IntelliJ IDEA.
* User: pereira
* Date: Jun 18, 2005
* Time: 9:11:24 PM
* <p/>
* Binary heap implementation of <code>PriorityQueue</code>.
* Based on algorithm in Corman, Leiserson, Rivest, and Stein (Section 6.5).
*/
public class MinHeap implements PriorityQueue {
private QueueElement[] elts;
private int size = 0;
private static final int MIN_CAPACITY = 16;
/**
* Create a binary heap with initial capacity <code>capacity</code>.
* The heap's capacity grows as needed to accomodate insertions.
*
* @param capacity initial capacity
*/
public MinHeap (int capacity)
{
if (capacity < MIN_CAPACITY)
capacity = MIN_CAPACITY;
elts = new QueueElement[capacity];
size = 0;
}
/**
* Create a binary heap with minimum initial capacity.
*/
public MinHeap ()
{
this (MIN_CAPACITY);
}
private void heapify (int i)
{
int l = 2 * i + 1;
int r = 2 * i + 2;
int first;
if (l < size && elts[l].getPriority () < elts[i].getPriority ())
first = l;
else
first = i;
if (r < size && elts[r].getPriority () < elts[first].getPriority ())
first = r;
if (first != i) {
QueueElement e = elts[i];
elts[i] = elts[first];
elts[i].setPosition (i);
elts[first] = e;
e.setPosition (first);
heapify (first);
}
}
public int size ()
{
return size;
}
public QueueElement min ()
{
if (size == 0)
throw new IndexOutOfBoundsException ("queue empty");
return elts[0];
}
public QueueElement extractMin ()
{
if (size == 0)
throw new IndexOutOfBoundsException ("queue empty");
QueueElement min = elts[0];
elts[0] = elts[--size];
elts[0].setPosition (0); // this is necessary in case elts[size-1] happens to be the best --cas
heapify (0);
min.setPosition (-1);
return min;
}
public void changePriority (QueueElement e, double priority)
{
if (!contains (e))
throw new IllegalArgumentException ("Element not in queue");
if (priority <= e.getPriority ()) {
decreaseKey (e, priority);
} else {
increaseKey (e, priority);
}
}
private void increaseKey (QueueElement e, double priority)
{
e.setPriority (priority);
heapify (e.getPosition ());
}
private void decreaseKey (QueueElement e, double priority)
{
e.setPriority (priority);
int i = e.getPosition ();
int j;
while (i > 0 && elts[j = (i - 1) / 2].getPriority () > elts[i].getPriority ()) {
QueueElement p = elts[j];
elts[j] = elts[i];
elts[j].setPosition (j);
elts[i] = p;
p.setPosition (i);
i = j;
}
}
public void insert (QueueElement e)
{
if (size == elts.length) {
QueueElement[] newElts = new QueueElement[size + size / 2];
for (int i = 0; i < size; i++)
newElts[i] = elts[i];
elts = newElts;
}
e.setPosition (size);
elts[size++] = e;
changePriority (e, e.getPriority ());
}
public boolean contains (QueueElement e)
{
int pos = e.getPosition ();
return pos >= 0 && pos < size && e == elts[pos];
}
public QueueElement[] toArray ()
{
QueueElement[] arr = new QueueElement[size ()];
System.arraycopy (elts, 0, arr, 0, size ());
return arr;
}
// for debugging --cas
private void checkHeap (int i)
{
int child = 2*i + 1;
if (child < size) {
assert elts[i].getPriority () <= elts [child].getPriority ();
checkHeap (child);
}
child = 2*i + 2;
if (child < size) {
assert elts[i].getPriority () <= elts [child].getPriority ();
checkHeap (child);
}
}
}