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
						
					
					
				/* 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;
 |