package flare.util.heap
{
/**
* A Fibonacci heap data structure for maintaining a sorted priority queue.
* For more about this particular implementation see
* <a target="_top" href="http://en.wikipedia.org/wiki/Fibonacci_heap">
* Wikipedia's Fibonacci Heap article</a>.
*/
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;
while (kids > 0) {
r = x.right;
x.left.right = x.right;
x.right.left = x.left;
x.left = _min;
x.right = _min.right;
_min.right = x;
x.right.left = x;
x.parent = null;
x = r;
kids--;
}
z.left.right = z.right;
z.right.left = z.left;
if (z == z.right) {
_min = null;
} else {
_min = z.right;
consolidate();
}
_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 arraySize:int = _size + 1;
var array:Array = new Array(arraySize);
var i:uint;
for (i=0; i<arraySize; i++)
array[i] = null;
var numRoots:int = 0, d:int;
var x:HeapNode = _min, y:HeapNode;
var next:HeapNode, temp:HeapNode;
if (x != null) {
numRoots++;
x = x.right;
while (x != _min) {
numRoots++;
x = x.right;
}
}
while (numRoots > 0) {
d = x.degree;
next = x.right;
while (array[d] != null) {
y = array[d];
if (x.key > y.key) {
temp = y;
y = x;
x = temp;
}
link(y, x);
array[d] = null;
d++;
}
array[d] = x;
x = next;
numRoots--;
}
_min = null;
for (i=0; i<arraySize; i++) {
if (array[i] != null) {
if (_min != null) {
array[i].left.right = array[i].right;
array[i].right.left = array[i].left;
array[i].left = _min;
array[i].right = _min.right;
_min.right = array[i];
array[i].right.left = array[i];
if (array[i].key < _min.key) {
_min = array[i];
}
} else {
_min = array[i];
}
}
}
}
private function cut(x:HeapNode, y:HeapNode):void
{
x.left.right = x.right;
x.right.left = x.left;
y.degree--;
if (y.child == x) {
y.child = x.right;
}
if (y.degree == 0) {
y.child = null;
}
x.left = _min;
x.right = _min.right;
_min.right = x;
x.right.left = x;
x.parent = null;
x.mark = false;
}
private function link(y:HeapNode, x:HeapNode):void
{
y.left.right = y.right;
y.right.left = y.left;
y.parent = x;
if (x.child == null) {
x.child = y;
y.right = y;
y.left = y;
} else {
y.left = x.child;
y.right = x.child.right;
x.child.right = y;
y.right.left = y;
}
x.degree++;
y.mark = false;
}
} }