/*
Copyright 2006 by Sean Luke and George Mason University
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package sim.util;
/*
* Heap.java
*
* Created: Fri Jan 25 2002
* By: Liviu Panait
*/
/**
* Implementations of Heap functions in Java. This code is derived
* from the HeapSort example algorithm in <i>Introduction to algorithms</i> by
* Cormen, Leiserson and Rivest. Intentionally very simple.
*
* @author Liviu Panait and Sean Luke
* @version 2.0
*/
public class Heap implements java.io.Serializable
{
private static final long serialVersionUID = 1;
// the keys
Comparable[] keys = null;
// the information associated with the keys
Object[] objects = null;
int numElem = 0;
public Comparable[] getKeys()
{
Comparable[] k = new Comparable[numElem];
System.arraycopy(keys,0,k,0,numElem);
return k;
}
public Object[] getObjects()
{
Object[] o = new Object[numElem];
System.arraycopy(objects,0,o,0,numElem);
return o;
}
// constructs the heap
public Heap()
{
this(new Comparable[0], new Object[0]);
}
// constructs the heap
public Heap( Comparable[] keys, Object[] objects )
{
if (keys.length != objects.length)
throw new IllegalArgumentException("keys and objects must be of the same length");
this.keys = keys;
this.objects = objects;
this.numElem = keys.length;
buildHeap();
}
// builds the heap
void buildHeap()
{
for( int i = numElem/2 ; i >= 1 ; i-- )
heapify( i, numElem );
}
void heapify( int i, int heapsize )
{
// make local
Object[] objects = this.objects;
Comparable[] keys = this.keys;
while( true )
{
int l = 2*i;
int r = 2*i+1;
int smallest;
if( l <= heapsize && keys[l-1].compareTo(keys[i-1]) < 0 ) //keys[l-1] < keys[i-1] )
smallest = l;
else
smallest = i;
if( r <= heapsize && keys[r-1].compareTo(keys[smallest-1]) < 0) // keys[r-1] < keys[smallest-1] )
smallest = r;
if( smallest != i )
{
// swap keys
Comparable tempkey = keys[i-1];
keys[i-1] = keys[smallest-1];
keys[smallest-1] = tempkey;
// swap info
Object temp = objects[i-1];
objects[i-1] = objects[smallest-1];
objects[smallest-1] = temp;
// recursive call.... :)
i = smallest;
}
else
return;
}
}
/** Returns the key value of the current min element. Returns null if there is no such element. Does not extract the element. */
public Comparable getMinKey()
{
if (numElem == 0) return null;
return keys[1-1];
}
/** Returns the current min element. Returns null if there is no such element. Does not extract the element. */
public Object getMin()
{
if (numElem == 0) return null;
return objects[1-1];
}
/* Removes elements in order and adds them to a Bag, so long as the provided
Comparable object is equal to their keys. As soon as this is not true, the Bag is returned.
You may provide a Bag -- putInHere -- to be filled in. */
Bag extractMin(Comparable comparable, Bag putInHere)
{
if (putInHere == null) putInHere = new Bag();
while( true )
{
Comparable comp = getMinKey();
if (comp == null || // ran out
comparable.compareTo(comp) != 0) // not the same value
return putInHere;
putInHere.add(extractMin());
}
}
/** Removes all key-equal minimum elements and adds them to a Bag, which is then is returned.
You may provide a Bag -- putInHere -- to be filled in. */
public Bag extractMin(Bag putInHere)
{
Comparable min = getMinKey();
if (min==null)
{
if (putInHere == null) return new Bag(0);
else return putInHere;
}
if (putInHere==null) putInHere = new Bag();
putInHere.add(extractMin());
return extractMin(min, putInHere);
}
/** Removes the first minimum element and its key from the heap, and returns the minimum element. Will return null if the heap is empty */
public Object extractMin()
{
// make local
int numElem = this.numElem;
Object[] objects = this.objects;
Comparable[] keys = this.keys;
if( numElem == 0 )
return null;
// remove the key
keys[1-1] = keys[numElem-1];
keys[numElem-1] = null; // 0;
// remove the info
Object result = objects[1-1];
objects[1-1] = objects[numElem-1];
objects[numElem-1] = null;
numElem--;
// rebuild heap
if (numElem > 1) heapify( 1, numElem ); // no need to heapify if there's only zero or one element!
// return the info with min key (which was also removed from the heap)
// put back
this.numElem = numElem;
return result;
}
/** Adds an element to the heap with the given key. */
public void add( Object elem, Comparable key )
{
// make local
int numElem = this.numElem;
Object[] objects = this.objects;
Comparable[] keys = this.keys;
numElem++;
if( (numElem-1) >= objects.length )
{
Object[] temp = new Object[ objects.length * 2 + 1];
System.arraycopy( objects, 0, temp, 0, objects.length );
objects = temp;
Comparable[] temptemp = new Comparable[ keys.length * 2 + 1];
System.arraycopy( keys, 0, temptemp, 0, keys.length );
keys = temptemp;
// objects and keys may have changed
this.objects = objects;
this.keys = keys;
}
int i = numElem;
if (i > 1) // no need to bubble up if there's only zero or one element!
{
while ( i > 1 && key.compareTo(keys[i/2-1]) < 0 ) // keys[i/2-1] > key )
{
objects[i-1] = objects[i/2-1];
keys[i-1] = keys[i/2-1];
i = i/2;
}
}
keys[i-1] = key;
objects[i-1] = elem;
// put back
this.numElem = numElem;
}
public int size()
{
return numElem;
}
public boolean isEmpty()
{
return (numElem==0);
}
public void clear()
{
int len = numElem;
// let go of the objects so they GC... perhaps we should just replace the arrays? dunno.
Object[] objects = this.objects;
Comparable[] keys = this.keys;
for(int x=0;x<len;x++)
{
objects[x] = null;
keys[x] = null;
}
numElem = 0;
}
/**
Produces a new heap which is the union of this heap with the other.
The original heaps are not modified. The new heap is returned.
*/
public Heap merge(Heap other)
{
int n = this.numElem + other.numElem;
Comparable[] combinedKeys = new Comparable[n];
Object[] combinedObjects = new Object[n];
System.arraycopy(keys, 0, combinedKeys, 0, this.numElem);
System.arraycopy(other.keys, 0, combinedKeys, this.numElem, other.numElem);
System.arraycopy(objects, 0, combinedObjects, 0, this.numElem);
System.arraycopy(other.objects, 0, combinedObjects, this.numElem, other.numElem);
return new Heap(combinedKeys, combinedObjects);
}
}