package flare.util.heap
{
/**
* A Fibonacci heap data structure for maintaining a sorted priority queue.
* For more about this particular implementation see
*
* Wikipedia's Fibonacci Heap article.
*/
public class FibonacciHeap
{
private var _min:HeapNode;
private var _size:int;
/** True if the heap is empty, false otherwise. */
public function get empty():Boolean
{
return _min == null;
}
/** The number of nodes contained in this heap. */
public function get size():int
{
return _size;
}
/**
* Clears the heap, removing all nodes.
*/
public function clear():void
{
_min = null;
_size = 0;
}
/**
* Decrease the key value for a heap node, changing its key and
* potentially re-configuring the heap structure
* @param x the heap node
* @param k the new key value for the node. If this value is greater
* than the node's current key value an error will be thrown.
*/
public function decreaseKey(x:HeapNode, k:Number):void
{
if (k > x.key)
throw new Error("Only lower key values allowed");
x.key = k;
var y:HeapNode = x.parent;
if ((y != null) && (x.key < y.key)) {
cut(x, y);
cascadingCut(y);
}
if (x.key < _min.key) {
_min = x;
}
}
/**
* Removes a node from the heap.
* @param x the heap node to remove
*/
public function remove(x:HeapNode):void
{
decreaseKey(x, Number.NEGATIVE_INFINITY);
removeMin();
}
/**
* Inserts a new node into the heap.
* @param data the data to associate with the heap node
* @param key the key value used to sort the heap node
* @return the newly added heap node
*/
public function insert(data:Object,
key:Number=Number.POSITIVE_INFINITY):HeapNode
{
var n:HeapNode = new HeapNode(data, key);
n.inHeap = true;
if (_min != null) {
n.left = _min;
n.right = _min.right;
_min.right = n;
n.right.left = n;
if (key < _min.key)
_min = n;
} else {
_min = n;
}
_size++;
return n;
}
/**
* Returns the heap node with the minimum key value.
* @return the heap node with the minimum key value
*/
public function min():HeapNode
{
return _min;
}
/**
* Removes and returns the heap node with the minimum key value.
* @return the heap node with the minimum key value
*/
public function removeMin():HeapNode
{
var z:HeapNode = _min;
if (z == null) return z;
var kids:int = z.degree;
var x:HeapNode = z.child;
var r:HeapNode;
// for each child of z do...
while (kids > 0) {
r = x.right;
// remove x from child list
x.left.right = x.right;
x.right.left = x.left;
// add x to root list of heap
x.left = _min;
x.right = _min.right;
_min.right = x;
x.right.left = x;
// set parent[x] to null
x.parent = null;
x = r;
kids--;
}
// remove z from root list of heap
z.left.right = z.right;
z.right.left = z.left;
if (z == z.right) {
_min = null;
} else {
_min = z.right;
consolidate();
}
// decrement size of heap and return
_size--;
z.inHeap = false;
return z;
}
/**
* Constructs the union of two fibonacci heaps.
* @param h1 the first heap
* @param h2 the second heap
* @return the union of the two heaps
*/
public static function union(h1:FibonacciHeap, h2:FibonacciHeap):FibonacciHeap
{
var h:FibonacciHeap = new FibonacciHeap();
if (h1 != null && h2 != null) {
h._min = h1._min;
if (h._min != null) {
if (h2._min != null) {
h._min.right.left = h2._min.left;
h2._min.left.right = h._min.right;
h._min.right = h2._min;
h2._min.left = h._min;
if (h2._min.key < h1._min.key)
h._min = h2._min;
}
} else {
h._min = h2._min;
}
h._size = h1._size + h2._size;
}
return h;
}
private function cascadingCut(y:HeapNode):void
{
var z:HeapNode = y.parent;
if (z != null) {
if (!y.mark) {
y.mark = true;
} else {
cut(y, z);
cascadingCut(z);
}
}
}
private function consolidate():void
{
var vectorSize:int = _size + 1;
var vector:Vector.