| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 | 
							- /**
 
-  * nodejs heap, classic array implementation
 
-  *
 
-  * Items are stored in a balanced binary tree packed into an array where
 
-  * node is at [i], left child is at [2*i], right at [2*i+1].  Root is at [1].
 
-  *
 
-  * Copyright (C) 2014-2020 Andras Radics
 
-  * Licensed under the Apache License, Version 2.0
 
-  */
 
- 'use strict';
 
- //module.exports = Heap;
 
- function isBeforeDefault( a, b ) { return a < b; }
 
- function Heap( opts ) {
 
-     if (!(this instanceof Heap)) return new Heap(opts);
 
-     if (typeof opts === 'function') opts = {compar: opts};
 
-     // copy out known options to not bind to caller object
 
-     this.options = !opts ? {} : {
 
-         compar: opts.compar,
 
-         comparBefore: opts.comparBefore,
 
-         freeSpace: opts.freeSpace,
 
-         size: opts.size,
 
-     };
 
-     opts = this.options;
 
-     var self = this;
 
-     this._isBefore = opts.compar ? function(a, b) { return opts.compar(a, b) < 0 } : opts.comparBefore || isBeforeDefault;
 
-     this._sortBefore = opts.compar || function(a, b) { return self._isBefore(a, b) ? -1 : 1 };
 
-     this._freeSpace = opts.freeSpace ? this._trimArraySize : false;
 
-     this._list = new Array(opts.size || 20);
 
-     // 14% slower to mix ints and pointers in an array, even if deleted
 
-     // this._list[0] = undefined;
 
-     this.length = 0;
 
- }
 
- Heap.prototype._list = null;
 
- Heap.prototype._compar = null;
 
- Heap.prototype._isBefore = null;
 
- Heap.prototype._freeSpace = null;
 
- Heap.prototype._sortBefore = null;
 
- Heap.prototype.length = 0;
 
- /*
 
-  * insert new item at end, and bubble up
 
-  */
 
- Heap.prototype.insert = function Heap_insert( item ) {
 
-     var idx = ++this.length;
 
-     return this._bubbleup(idx, item);
 
- };
 
- Heap.prototype._bubbleup = function _bubbleup( idx, item ) {
 
-     var list = this._list;
 
-     list[idx] = item;
 
-     while (idx > 1) {
 
-         if (!(this._isBefore(item, list[idx >> 1]))) break;
 
-         list[idx] = list[idx >> 1];
 
-         idx = idx >> 1;
 
-     }
 
-     list[idx] = item;
 
- };
 
- Heap.prototype.append = Heap.prototype.insert;
 
- Heap.prototype.push = Heap.prototype.insert;
 
- Heap.prototype.unshift = Heap.prototype.insert;
 
- Heap.prototype.enqueue = Heap.prototype.insert;
 
- Heap.prototype.peek = function Heap_peek( ) {
 
-     return this.length > 0 ? this._list[1] : undefined;
 
- };
 
- Heap.prototype.size = function Heap_size( ) {
 
-     return this.length;
 
- };
 
- /*
 
-  * return the root, and bubble down last item from top root position
 
-  * when bubbling down, r: root idx, c: child sub-tree root idx, cv: child root value
 
-  * Note that the child at (c == this.length) does not have to be tested in the loop,
 
-  * since its value is the one being bubbled down, so can loop `while (c < len)`.
 
-  */
 
- Heap.prototype.remove = function Heap_remove( ) {
 
-     var len = this.length;
 
-     if (len < 1) return undefined;
 
-     return this._bubbledown(1, len);
 
- /**
 
-     // experiment: ripple down hole from root, bubble up last from hole
 
-     var list = this._list;
 
-     var ret = list[1];
 
-     var holeIdx = this._rippleup(1, len);
 
-     this._bubbleup(holeIdx, list[this.length--]);
 
-     if (this._freeSpace) this._freeSpace(list, len);
 
-     return ret;
 
- /**/
 
- };
 
- Heap.prototype._bubbledown = function _bubbledown( r, len ) {
 
-     var list = this._list, ret = list[r], itm = list[len];
 
-     var c, _isBefore = this._isBefore;
 
-     while ((c = r << 1) < len) {
 
-         var cv = list[c], cv1 = list[c+1];
 
-         if (_isBefore(cv1, cv)) { c++; cv = cv1; }
 
-         if (!(_isBefore(cv, itm))) break;
 
-         list[r] = cv;
 
-         r = c;
 
-     }
 
-     list[r] = itm;
 
-     list[len] = 0;
 
-     this.length = --len;
 
-     if (this._freeSpace) this._freeSpace(this._list, this.length);
 
-     return ret;
 
- };
 
- /**
 
- Heap.prototype._rippleup = function _rippleup( r, len ) {
 
-     var list = this._list;
 
-     var c, _isBefore = this._isBefore;
 
-     while ((c = r << 1) < len) {
 
-         var cv = list[c];
 
-         var cv1 = list[c+1];
 
-         if (_isBefore(cv1, cv)) { cv = cv1; c = c+1 }
 
-         list[r] = cv;
 
-         r = c;
 
-     }
 
-     if (c === len) {
 
-         list[r] = list[c];
 
-         r = c;
 
-     }
 
-     return r;
 
- };
 
- /**/
 
- Heap.prototype.shift = Heap.prototype.remove;
 
- Heap.prototype.pop = Heap.prototype.remove;
 
- Heap.prototype.dequeue = Heap.prototype.remove;
 
- // builder, not initializer: appends items, not replaces
 
- Heap.prototype.fromArray = function fromArray( array, base, bound ) {
 
-     var base = base || 0;
 
-     var bound = bound || array.length;
 
-     for (var i=base; i<bound; i++) this.insert(array[i]);
 
- }
 
- Heap.prototype.toArray = function toArray( limit ) {
 
-     limit = typeof limit === 'number' ? limit + 1 : this.length + 1;
 
-     return this._list.slice(1, limit);
 
- }
 
- Heap.prototype.copy = function copy( ) {
 
-     var ret = new Heap(this.options);
 
-     for (var i = 1; i <= this.length; i++) ret._list[i] = this._list[i];
 
-     ret.length = this.length;
 
-     return ret;
 
- }
 
- Heap.prototype.peekHead = function peekHead( n ) {
 
-     // todo: think about a more efficient approach than cloning the list
 
-     // todo: would be more efficient to sort the whole list if peeking at say over 50% of the items
 
-     var copy = this.copy();
 
-     var item, head = new Array();
 
-     while (head.length < n && (item = copy.shift()) !== undefined) {
 
-         head.push(item);
 
-     }
 
-     return head;
 
- }
 
- // sort the contents of the storage array
 
- // Trim the array for the sort, ensure first item is smallest, sort.
 
- // Note that sorted order is valid heap format.
 
- // Truncating the list is faster than copy-out/copy-in.
 
- // node-v11 and up are 5x faster to sort 1k numbers than v10.
 
- Heap.prototype.sort = function sort( ) {
 
-     if (this.length < 3) return;
 
-     this._list.splice(this.length + 1);
 
-     this._list[0] = this._list[1];
 
-     this._list.sort(this._sortBefore);
 
-     this._list[0] = 0;
 
- }
 
- // generate a uniformly distributed subsample of k items (Reservoir Algorithm)
 
- // First select the first k items, then once have k samples
 
- // randomly replace a selection with the i-th item i>k, with k/i probability.
 
- // Eg: pick 2 [1,2,3]: get [1,2], replace 3 with 2/3 probability into slot [0] or [1].
 
- // Note that this._list is indexed 1..N, but samples are indexed 0..k-1
 
- // Note: if k is much smaller than .length, would be faster to
 
- //   generate k unique random array indexes than N random values.
 
- Heap.prototype.subsample = function subsample( k, options ) {
 
-     options = options || {};
 
-     var samples = new Array();
 
-     if (k > this.length) k = this.length;
 
-     for (var i = 1; i <= k; i++) samples[i - 1] = this._list[i];
 
-     for (var i = k + 1; i <= this.length; i++) {
 
-         var j = Math.floor(Math.random() * i);
 
-         if (j < k) samples[j] = this._list[i];
 
-     }
 
-     if (options.sort) samples.sort(this._sortBefore);
 
-     return samples;
 
- }
 
- /*
 
-  * Free unused storage slots in the _list.
 
-  * The default is to unconditionally gc, use the options to omit when not useful.
 
-  */
 
- Heap.prototype.gc = function Heap_gc( options ) {
 
-     if (!options) options = {};
 
-     var minListLength = options.minLength;      // smallest list that will be gc-d
 
-     if (minListLength === undefined) minListLength = 0;
 
-     var minListFull = options.minFull;          // list utilization below which to gc
 
-     if (minListFull === undefined) minListFull = 1.00;
 
-     if (this._list.length >= minListLength && (this.length < this._list.length * minListFull)) {
 
-         // gc reallocates the array to free the unused storage slots at the end
 
-         // use splice to actually free memory; 7% slower than setting .length
 
-         // note: list.slice makes the array slower to insert to??  splice is better
 
-         this._list.splice(this.length+1, this._list.length);
 
-     }
 
- }
 
- Heap.prototype._trimArraySize = function Heap__trimArraySize( list, len ) {
 
-     if (len > 10000 && list.length > 4 * len) {
 
-         // use slice to actually free memory; 7% slower than setting .length
 
-         // note: list.slice makes the array slower to insert to??  splice is better
 
-         list.splice(len+1, list.length);
 
-     }
 
- }
 
- Heap.prototype._check = function Heap__check( ) {
 
-     var isBefore = this._isBefore;
 
-     var _compar = this._sortBefore;
 
-     var i, p, fail = 0;
 
-     for (i=this.length; i>1; i--) {
 
-         // error if parent should go after child, but not if don`t care
 
-         p = i >>> 1;
 
-         // swapping the values must change their ordering, otherwise the
 
-         // comparison is a tie.  (Ie, consider the ordering func (a <= b)
 
-         // that for some values reports both that a < b and b < a.)
 
-         if (_compar(this._list[p], this._list[i]) > 0 &&
 
-             _compar(this._list[i], this._list[p]) < 0)
 
-         {
 
-             fail = i;
 
-         }
 
-     }
 
-     if (fail) console.log("failed at", (fail >>> 1), fail);
 
-     return !fail;
 
- }
 
- // optimize access
 
- Heap.prototype = toStruct(Heap.prototype);
 
- function toStruct(o) { return toStruct.prototype = o }
 
 
  |