UNPKG

basicprimitives

Version:

Basic Primitives Diagrams for JavaScript - data visualization components library that implements organizational chart and multi-parent dependency diagrams, contains implementations of JavaScript Controls and PDF rendering plugins.

350 lines (312 loc) 9.14 kB
/** * Heap result object * @class HeapResult * @property {string} key Key * @property {number} priority Priority * @property {Object} item Context object */ export function HeapResult (node) { this.key = node.key; this.priority = node.priority; this.item = node.item; } /** * Creates Fibonacci Heap structure * @class FibonacciHeap * * @param {boolean} isMaximum Is maximum heap * @returns {FibonacciHeap} Returns new FibonacciHeap object */ export default function FibonacciHeap(isMaximum) { var root = null, count = 0, nodes = {}; function Node(key, priority, item) { this.key = key; this.priority = priority; this.item = item; this.degree = 0; this.marked = false; this.parent = null; this.child = null; this.left = null; this.right = null; } /** * Validates internal structure consistency. * * @returns {boolean} Returns true if structure pass data consistency check. */ function validate() { var totalNodes = 0; for (var key in nodes) { if (nodes.hasOwnProperty(key)) { var node = nodes[key]; totalNodes += 1; if (node.child != null) { if (!nodes.hasOwnProperty(node.child)) { throw "Child does not exists"; } var ref = nodes[node.child]; if (ref.parent != node.key) { throw "Child references wrong parent"; } } if (node.parent != null) { if (!nodes.hasOwnProperty(node.parent)) { throw "Parent does not exists"; } } if (node.left != null) { if (!nodes.hasOwnProperty(node.left)) { throw "Left does not exists"; } ref = nodes[node.left]; if (ref.right != node.key) { throw "Left references wrong right"; } } if (node.right != null) { if (!nodes.hasOwnProperty(node.right)) { throw "Right does not exists"; } ref = nodes[node.right]; if (ref.left != node.key) { throw "Right references wrong left"; } } } } if (root == null && totalNodes > 0) { throw "Orphans"; } if (root != null) { if (!nodes.hasOwnProperty(root)) { throw "Root node does not exists"; } node = nodes[root]; if (node.parent != null) { throw "Root node has parent reference"; } var children = [root]; var processed = {}; var totalChildren = 0; while (children.length > 0) { var newChildren = []; for (var index = 0, len = children.length; index < len; index += 1) { var child = nodes[children[index]]; while (!processed.hasOwnProperty(child.key)) { processed[child.key] = true; totalChildren += 1; if (child.child != null) { newChildren.push(child.child); } child = nodes[child.right]; } } children = newChildren; } if (totalNodes != totalChildren) { throw "Tree has loops or orpants"; } } } /** * Adds a new item into the heap * @param {string} key A key of the new element * @param {number} priority A priority of the new element * @param {object} item A context object of the new element */ function add(key, priority, item) { if (nodes.hasOwnProperty(key)) { throw "Duplicate keys are not supported!"; } var newNode = new Node(key, priority, item); nodes[key] = newNode; if (root == null) { newNode.left = key; newNode.right = key; root = key; } else { var rootNode = nodes[root]; _insert(rootNode, newNode); if (isMaximum ? rootNode.priority < newNode.priority : rootNode.priority > newNode.priority) { root = key; } } count += 1; } function _insert(node, newNode) { var rightNode = nodes[node.right]; newNode.right = node.right; newNode.left = node.key; node.right = newNode.key; rightNode.left = newNode.key; } function _exclude(node) { var prevNode = nodes[node.left], nextNode = nodes[node.right]; prevNode.right = nextNode.key; nextNode.left = prevNode.key; node.right = node.key; node.left = node.key; } /** * Gets priority of element by key * @param {string} key The element key * @returns {number} Returns priority of the element */ function getPriority(key) { var result = null; if (nodes.hasOwnProperty(key)) { result = nodes[key].priority; } return result; } /** * Returns heap root element * * @returns {HeapResult} Returns root element of the heap */ function heapRoot() { var result = null; if (root != null) { result = new HeapResult(nodes[root]); } return result; } /** * Returns heap root element with removal * * @returns {HeapResult} Returns root element of the heap */ function extractRoot() { var result = heapRoot(); if (result != null) { var rootNode = nodes[root], nextNode = nodes[rootNode.right]; if (rootNode.child != null) { var childNode = nodes[rootNode.child], childNodeLeft = nodes[childNode.left]; rootNode.right = childNode.key; nextNode.left = childNodeLeft.key; childNode.left = rootNode.key; childNodeLeft.right = nextNode.key; _exclude(rootNode); delete nodes[rootNode.key]; root = null; _consolidate(childNode.key); } else { _exclude(rootNode); delete nodes[rootNode.key]; root = null; if (nextNode.key != rootNode.key) { _consolidate(nextNode.key); } } count -= 1; } return result; } function _consolidate(startKey) { var pairs = [], pairedNode, processed = {}, key = startKey; while (!processed.hasOwnProperty(key)) { var node = nodes[key], nextKey = node.right; processed[key] = true; node.parent = null; while ((pairedNode = pairs[node.degree]) != null) { if (isMaximum ? node.priority > pairedNode.priority : node.priority < pairedNode.priority) { _union(node, pairedNode); } else { _union(pairedNode, node); node = pairedNode; } pairs[node.degree - 1] = null; } pairs[node.degree] = node; if (root == null || nodes[root] == null || (isMaximum ? nodes[root].priority <= node.priority : nodes[root].priority >= node.priority)) { root = node.key; } key = nextKey; } } function _union(node1, node2) { node1.degree += 1; _exclude(node2); var child = nodes[node1.child]; if (child != null) { _insert(child, node2); if (isMaximum ? child.priority < node2.priority : child.priority > node2.priority) { node1.child = node2.key; } } else { node1.child = node2.key; } node2.parent = node1.key; } /** * Sets priority of an element by key * @param {string} key The key of the element * @param {number} priority Priority */ function setPriority(key, priority) { var node = nodes[key]; if (isMaximum ? node.priority > priority : node.priority < priority) { throw "Priority increase is not supported"; } node.priority = priority; if (node.parent != null) { var parentNode = nodes[node.parent]; if (isMaximum ? parentNode.priority < node.priority : parentNode.priority > node.priority) { _cut(parentNode, node); _cascadeCut(parentNode); } } if (isMaximum ? nodes[root].priority < node.priority : nodes[root].priority > node.priority) { root = node.key; } } function _cut(parentNode, node) { node.marked = false; node.parent = null; if (node.right == node.key) { parentNode.child = null; } else { parentNode.child = node.right; _exclude(node); } parentNode.degree -= 1; _insert(nodes[root], node); } function _cascadeCut(node) { if (node.parent != null) { if (node.marked) { var parentNode = nodes[node.parent]; _cut(parentNode, node); _cascadeCut(parentNode); } else { node.marked = true; } } } /** * Deletes heap element by key * @param {string} key The Key */ function deleteKey(key) { setPriority(key, isMaximum ? Infinity : -1); extractRoot(); } return { add: add, getPriority: getPriority, setPriority: setPriority, heapRoot: heapRoot, extractRoot: extractRoot, deleteKey: deleteKey, validate: validate }; };