You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					321 lines
				
				6.3 KiB
			
		
		
			
		
	
	
					321 lines
				
				6.3 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/* eslint no-constant-condition: 0 */
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Mnemonist Fibonacci Heap
							 | 
						||
| 
								 | 
							
								 * =========================
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Fibonacci heap implementation.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								var comparators = require('./utils/comparators.js'),
							 | 
						||
| 
								 | 
							
								    forEach = require('obliterator/foreach');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var DEFAULT_COMPARATOR = comparators.DEFAULT_COMPARATOR,
							 | 
						||
| 
								 | 
							
								    reverseComparator = comparators.reverseComparator;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Fibonacci Heap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function FibonacciHeap(comparator) {
							 | 
						||
| 
								 | 
							
								  this.clear();
							 | 
						||
| 
								 | 
							
								  this.comparator = comparator || DEFAULT_COMPARATOR;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof this.comparator !== 'function')
							 | 
						||
| 
								 | 
							
								    throw new Error('mnemonist/FibonacciHeap.constructor: given comparator should be a function.');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to clear the heap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @return {undefined}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FibonacciHeap.prototype.clear = function() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Properties
							 | 
						||
| 
								 | 
							
								  this.root = null;
							 | 
						||
| 
								 | 
							
								  this.min = null;
							 | 
						||
| 
								 | 
							
								  this.size = 0;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Function used to create a node.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any}    item - Target item.
							 | 
						||
| 
								 | 
							
								 * @return {object}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function createNode(item) {
							 | 
						||
| 
								 | 
							
								  return {
							 | 
						||
| 
								 | 
							
								    item: item,
							 | 
						||
| 
								 | 
							
								    degree: 0
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Function used to merge the given node with the root list.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {FibonacciHeap} heap - Target heap.
							 | 
						||
| 
								 | 
							
								 * @param {Node}          node - Target node.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function mergeWithRoot(heap, node) {
							 | 
						||
| 
								 | 
							
								  if (!heap.root) {
							 | 
						||
| 
								 | 
							
								    heap.root = node;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  else {
							 | 
						||
| 
								 | 
							
								    node.right = heap.root.right;
							 | 
						||
| 
								 | 
							
								    node.left = heap.root;
							 | 
						||
| 
								 | 
							
								    heap.root.right.left = node;
							 | 
						||
| 
								 | 
							
								    heap.root.right = node;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to push an item into the heap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {any}    item - Item to push.
							 | 
						||
| 
								 | 
							
								 * @return {number}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FibonacciHeap.prototype.push = function(item) {
							 | 
						||
| 
								 | 
							
								  var node = createNode(item);
							 | 
						||
| 
								 | 
							
								  node.left = node;
							 | 
						||
| 
								 | 
							
								  node.right = node;
							 | 
						||
| 
								 | 
							
								  mergeWithRoot(this, node);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!this.min || this.comparator(node.item, this.min.item) <= 0)
							 | 
						||
| 
								 | 
							
								    this.min = node;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return ++this.size;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to get the "first" item of the heap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @return {any}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FibonacciHeap.prototype.peek = function() {
							 | 
						||
| 
								 | 
							
								  return this.min ? this.min.item : undefined;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Function used to consume the given linked list.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {Node} head - Head node.
							 | 
						||
| 
								 | 
							
								 * @param {array}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function consumeLinkedList(head) {
							 | 
						||
| 
								 | 
							
								  var nodes = [],
							 | 
						||
| 
								 | 
							
								      node = head,
							 | 
						||
| 
								 | 
							
								      flag = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (true) {
							 | 
						||
| 
								 | 
							
								    if (node === head && flag)
							 | 
						||
| 
								 | 
							
								      break;
							 | 
						||
| 
								 | 
							
								    else if (node === head)
							 | 
						||
| 
								 | 
							
								      flag = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    nodes.push(node);
							 | 
						||
| 
								 | 
							
								    node = node.right;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return nodes;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Function used to remove the target node from the root list.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {FibonacciHeap} heap - Target heap.
							 | 
						||
| 
								 | 
							
								 * @param {Node}          node - Target node.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function removeFromRoot(heap, node) {
							 | 
						||
| 
								 | 
							
								  if (heap.root === node)
							 | 
						||
| 
								 | 
							
								    heap.root = node.right;
							 | 
						||
| 
								 | 
							
								  node.left.right = node.right;
							 | 
						||
| 
								 | 
							
								  node.right.left = node.left;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Function used to merge the given node with the child list of a root node.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {Node} parent - Parent node.
							 | 
						||
| 
								 | 
							
								 * @param {Node} node   - Target node.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function mergeWithChild(parent, node) {
							 | 
						||
| 
								 | 
							
								  if (!parent.child) {
							 | 
						||
| 
								 | 
							
								    parent.child = node;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  else {
							 | 
						||
| 
								 | 
							
								    node.right = parent.child.right;
							 | 
						||
| 
								 | 
							
								    node.left = parent.child;
							 | 
						||
| 
								 | 
							
								    parent.child.right.left = node;
							 | 
						||
| 
								 | 
							
								    parent.child.right = node;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Function used to link one node to another in the root list.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {FibonacciHeap} heap - Target heap.
							 | 
						||
| 
								 | 
							
								 * @param {Node}          y - Y node.
							 | 
						||
| 
								 | 
							
								 * @param {Node}          x - X node.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function link(heap, y, x) {
							 | 
						||
| 
								 | 
							
								  removeFromRoot(heap, y);
							 | 
						||
| 
								 | 
							
								  y.left = y;
							 | 
						||
| 
								 | 
							
								  y.right = y;
							 | 
						||
| 
								 | 
							
								  mergeWithChild(x, y);
							 | 
						||
| 
								 | 
							
								  x.degree++;
							 | 
						||
| 
								 | 
							
								  y.parent = x;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Function used to consolidate the heap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {FibonacciHeap} heap - Target heap.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function consolidate(heap) {
							 | 
						||
| 
								 | 
							
								  var A = new Array(heap.size),
							 | 
						||
| 
								 | 
							
								      nodes = consumeLinkedList(heap.root),
							 | 
						||
| 
								 | 
							
								      i, l, x, y, d, t;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 0, l = nodes.length; i < l; i++) {
							 | 
						||
| 
								 | 
							
								    x = nodes[i];
							 | 
						||
| 
								 | 
							
								    d = x.degree;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    while (A[d]) {
							 | 
						||
| 
								 | 
							
								      y = A[d];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (heap.comparator(x.item, y.item) > 0) {
							 | 
						||
| 
								 | 
							
								        t = x;
							 | 
						||
| 
								 | 
							
								        x = y;
							 | 
						||
| 
								 | 
							
								        y = t;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      link(heap, y, x);
							 | 
						||
| 
								 | 
							
								      A[d] = null;
							 | 
						||
| 
								 | 
							
								      d++;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    A[d] = x;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 0; i < heap.size; i++) {
							 | 
						||
| 
								 | 
							
								    if (A[i] && heap.comparator(A[i].item, heap.min.item) <= 0)
							 | 
						||
| 
								 | 
							
								      heap.min = A[i];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Method used to retrieve & remove the "first" item of the heap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @return {any}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FibonacciHeap.prototype.pop = function() {
							 | 
						||
| 
								 | 
							
								  if (!this.size)
							 | 
						||
| 
								 | 
							
								    return undefined;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var z = this.min;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (z.child) {
							 | 
						||
| 
								 | 
							
								    var nodes = consumeLinkedList(z.child),
							 | 
						||
| 
								 | 
							
								        node,
							 | 
						||
| 
								 | 
							
								        i,
							 | 
						||
| 
								 | 
							
								        l;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (i = 0, l = nodes.length; i < l; i++) {
							 | 
						||
| 
								 | 
							
								      node = nodes[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      mergeWithRoot(this, node);
							 | 
						||
| 
								 | 
							
								      delete node.parent;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  removeFromRoot(this, z);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (z === z.right) {
							 | 
						||
| 
								 | 
							
								    this.min = null;
							 | 
						||
| 
								 | 
							
								    this.root = null;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  else {
							 | 
						||
| 
								 | 
							
								    this.min = z.right;
							 | 
						||
| 
								 | 
							
								    consolidate(this);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.size--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return z.item;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Convenience known methods.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FibonacciHeap.prototype.inspect = function() {
							 | 
						||
| 
								 | 
							
								  var proxy = {
							 | 
						||
| 
								 | 
							
								    size: this.size
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (this.min && 'item' in this.min)
							 | 
						||
| 
								 | 
							
								    proxy.top = this.min.item;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Trick so that node displays the name of the constructor
							 | 
						||
| 
								 | 
							
								  Object.defineProperty(proxy, 'constructor', {
							 | 
						||
| 
								 | 
							
								    value: FibonacciHeap,
							 | 
						||
| 
								 | 
							
								    enumerable: false
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return proxy;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if (typeof Symbol !== 'undefined')
							 | 
						||
| 
								 | 
							
								  FibonacciHeap.prototype[Symbol.for('nodejs.util.inspect.custom')] = FibonacciHeap.prototype.inspect;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Fibonacci Maximum Heap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @constructor
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function MaxFibonacciHeap(comparator) {
							 | 
						||
| 
								 | 
							
								  this.clear();
							 | 
						||
| 
								 | 
							
								  this.comparator = comparator || DEFAULT_COMPARATOR;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof this.comparator !== 'function')
							 | 
						||
| 
								 | 
							
								    throw new Error('mnemonist/FibonacciHeap.constructor: given comparator should be a function.');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.comparator = reverseComparator(this.comparator);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								MaxFibonacciHeap.prototype = FibonacciHeap.prototype;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Static @.from function taking an arbitrary iterable & converting it into
							 | 
						||
| 
								 | 
							
								 * a heap.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {Iterable} iterable   - Target iterable.
							 | 
						||
| 
								 | 
							
								 * @param  {function} comparator - Custom comparator function.
							 | 
						||
| 
								 | 
							
								 * @return {FibonacciHeap}
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FibonacciHeap.from = function(iterable, comparator) {
							 | 
						||
| 
								 | 
							
								  var heap = new FibonacciHeap(comparator);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  forEach(iterable, function(value) {
							 | 
						||
| 
								 | 
							
								    heap.push(value);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return heap;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								MaxFibonacciHeap.from = function(iterable, comparator) {
							 | 
						||
| 
								 | 
							
								  var heap = new MaxFibonacciHeap(comparator);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  forEach(iterable, function(value) {
							 | 
						||
| 
								 | 
							
								    heap.push(value);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return heap;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Exporting.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								FibonacciHeap.MinFibonacciHeap = FibonacciHeap;
							 | 
						||
| 
								 | 
							
								FibonacciHeap.MaxFibonacciHeap = MaxFibonacciHeap;
							 | 
						||
| 
								 | 
							
								module.exports = FibonacciHeap;
							 |