class FibonacciHeap {
constructor() {
this.root_list = null;
this.min_node = null;
this.total_nodes = 0;
}
merge_with_root_list(node) {
if (this.root_list == null)
this.root_list = node;
else {
node.right = this.root_list.right;
node.left = this.root_list;
if (this.root_list.right != null)
this.root_list.right.left = node;
this.root_list.right = node;
}
}
insert(value) {
let n = new FibonacciNode(value);
n.left = n.right = n;
this.merge_with_root_list(n);
if (this.min_node == null || n.value < this.min_node.value)
this.min_node = n;
this.total_nodes++;
}
find_min() {
return this.min_node;
}
*iterate(head) {
let node = head;
let stop = head;
let flag = false;
while (true) {
if (node == stop && flag == true)
break;
if (node == stop)
flag = true;
yield node;
node = node.right;
}
}
make_array(node) {
let A = [];
let iterator = this.iterate(node);
let curr = iterator.next();
while (curr.done === false) {
A.push(curr.value);
curr = iterator.next();
}
return A;
}
remove_from_root_list(node) {
if (node == this.root_list)
this.root_list = node.right;
node.left.right = node.right;
node.right.left = node.left;
}
merge_with_child_list(parent, node) {
if (parent.child == null)
parent.child = node;
else {
node.right = parent.child.right;
node.left = parent.child;
parent.child.right.left = node;
parent.child.right = node;
}
}
heap_link(y, x) {
this.remove_from_root_list(y);
y.left = y.right = y;
this.merge_with_child_list(x, y);
x.degree++;
y.parent = x;
}
consolidate() {
let A = [];
for(let i=0; i < this.total_nodes; i++)
A.push(null);
let nodes = this.make_array(this.root_list);
for(let i=0; i < nodes.length; i++) {
let x = nodes[i];
let d = x.degree;
while (A[d] != null) {
let y = A[d];
if (x.value > y.value) {
let temp = x;
x = y;
y = temp;
}
this.heap_link(y, x);
A[d] = null;
d++;
}
A[d] = x;
}
for(let i=0; i < A.length; i++) {
if (A[i] != null) {
if (A[i].value < this.min_node.value) {
this.min_node = A[i];
}
}
}
}
extract_min() {
let min = this.min_node;
if (min != null) {
if (min.child != null) {
let children = this.make_array(min.child);
for(let i=0; i < children.length; i++) {
this.merge_with_root_list(children[i]);
children[i].parent = null;
}
}
this.remove_from_root_list(min);
if (min == min.right)
this.min_node = this.root_list = null;
else {
this.min_node = min.right;
this.consolidate();
}
this.total_nodes--;
}
return min;
}
remove_from_child_list(parent, node) {
if (parent.child == parent.child.right)
parent.child = null;
if (parent.child == node) {
parent.child = node.right;
node.right.parent = parent;
}
else {
node.left.right = node.right;
node.right.left = node.left;
}
}
cut(node, parent) {
this.remove_from_child_list(parent, node);
parent.degree--;
this.merge_with_root_list(node);
node.parent = null;
node.mark = false;
}
cascading_cut(node) {
let parent = node.parent;
if (parent != null) {
if (node.mark == false)
node.mark = true;
else {
this.cut(node, parent);
this.cascading_cut(parent);
}
}
}
decrease_key(node, new_value) {
if (new_value > node.value)
return null;
node.value = new_value;
let parent = node.parent;
if (parent != null && node.value < parent.value) {
this.cut(node, parent);
this.cascading_cut(parent);
}
if (node.value < this.min_node.value)
this.min_node = node;
}
delete_node(node) {
let parent = node.parent;
let child = node.child;
let A = [];
if (child != null)
A = this.make_array(child);
if (parent == null)
this.remove_from_root_list(node);
if (parent != null) {
this.remove_from_child_list(parent, node);
parent.degree--;
if (parent.mark == false && parent.parent != null)
parent.mark = true;
}
while (parent.mark === true) {
A.push(parent);
this.remove_from_child_list(parent.parent, parent);
parent = parent.parent;
}
for(let i=0; i < A.length; i++) {
this.merge_with_root_list(A[i]);
A[i].parent = null;
A[i].mark = false;
}
}
merge(h2) {
let h1 = new FibonacciHeap();
h1.root_list = this.root_list;
h1.min_node = this.min_node;
let last = h2.root_list.left;
h2.root_list.left = h1.root_list.left;
h1.root_list.left.right = h2.root_list;
h1.root_list.left = last;
h1.root_list.left.right = h1.root_list
if (h2.min_node < h1.min_node)
h1.min_node = h2.min_node;
h1.total_nodes = this.total_nodes + h2.total_nodes;
return h1;
}
}