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