heapster
Version:
Heap data structure so hype it's using ES 2015. Gluten and dependency free.
374 lines (323 loc) • 8.89 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var comparator = function comparator(a, b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
};
var symbols = {
index: Symbol && Symbol('index')
};
function isNumber(value) {
return typeof value === 'number';
}
function indexOf(arr, elem, sym) {
if (sym && isNumber(elem[sym])) {
return elem[sym];
} else {
return arr.indexOf(elem);
}
}
function updateIndexAt(arr, index, sym) {
if (sym && typeof arr[index] === 'object') {
arr[index][sym] = index;
}
}
// O(log(n))
function siftUp(arr, comp, pos, sym) {
var elem = arr[pos];
while (pos > 0) {
var parentPos = pos - 1 >> 1;
var _parent = arr[parentPos];
if (pos > 0 && comp(elem, _parent) > 0) {
arr[pos] = _parent;
updateIndexAt(arr, pos, sym);
pos = parentPos;
} else {
break;
}
}
arr[pos] = elem;
updateIndexAt(arr, pos, sym);
return arr;
}
// O(log(n))
function siftDown(_x, _x2, _x3, _x4, _x5) {
var _again = true;
_function: while (_again) {
var arr = _x,
comp = _x2,
pos = _x3,
end = _x4,
sym = _x5;
_again = false;
if (!isNumber(end)) {
sym = end;
end = arr.length;
}
var largest = undefined;
var left = 2 * pos + 1,
right = 2 * pos + 2;
if (left < end && comp(arr[left], arr[pos]) > 0) {
largest = left;
} else {
largest = pos;
}
if (right < end && comp(arr[right], arr[largest]) > 0) {
largest = right;
}
if (largest === pos) {
updateIndexAt(arr, pos, sym);
return arr;
} else {
var tmp = arr[pos];
arr[pos] = arr[largest];
arr[largest] = tmp;
updateIndexAt(arr, pos, sym);
updateIndexAt(arr, largest, sym);
_x = arr;
_x2 = comp;
_x3 = largest;
_x4 = end;
_x5 = sym;
_again = true;
largest = left = right = tmp = undefined;
continue _function;
}
}
}
var Heapster = (function () {
function Heapster(elems, comp, opts) {
_classCallCheck(this, Heapster);
if (!Array.isArray(elems)) {
opts = comp;
comp = elems;
elems = [];
}
if (typeof comp !== 'function') {
opts = comp;
comp = comparator;
}
if (opts === undefined) {
opts = {};
}
this.comparator = comp;
this.symbols = {};
if (opts.indexed) {
this.symbols.index = symbols.index;
}
this.elements = Heapster.heapify(elems.slice(0), this.comparator, this.symbols.index);
}
// O(n.log(n))
_createClass(Heapster, [{
key: 'size',
// O(1)
value: function size() {
return this.elements.length;
}
// O(1)
}, {
key: 'isEmpty',
value: function isEmpty() {
return this.size() === 0;
}
// O(1)
}, {
key: 'clean',
value: function clean(elem) {
return Heapster.clean(elem);
}
// get: O(1)
// set: O(log(n))
}, {
key: 'root',
value: function root(elem) {
if (elem !== undefined) {
var first = this.root();
if (first === undefined || this.comparator(first, elem) < 0) {
return elem;
} else {
this.elements[0] = elem;
siftDown(this.elements, this.comparator, 0, this.symbols.index);
return first;
}
}
return this.elements[0];
}
// O(log(n)) for each element
}, {
key: 'push',
value: function push() {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _len = arguments.length, elems = Array(_len), _key = 0; _key < _len; _key++) {
elems[_key] = arguments[_key];
}
for (var _iterator = elems[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var elem = _step.value;
this.elements.push(elem);
siftUp(this.elements, this.comparator, this.size() - 1, this.symbols.index);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return this.size();
}
// O(log(n))
}, {
key: 'add',
value: function add(elem) {
this.push(elem);
return this;
}
// O(log(n))
}, {
key: 'pop',
value: function pop() {
return this.root(this.elements.pop());
}
// O(1)
}, {
key: 'clone',
value: function clone() {
var result = new Heapster(this.comparator);
result.elements = this.elements.slice(0);
return result;
}
// O(n) or O(1)
}, {
key: 'has',
value: function has(elem) {
if (this.symbols.index && typeof elem === 'object') {
return isNumber(elem[this.symbols.index]) && elem === this.elements[elem[this.symbols.index]];
} else {
return this.elements.indexOf(elem) > -1;
}
}
// O(n) or O(log(n)) if indexed
}, {
key: 'update',
value: function update(elem) {
return this.updateAt(indexOf(this.elements, elem, this.symbols.index), elem);
}
// O(log(n))
}, {
key: 'updateAt',
value: function updateAt(index, value) {
if (index > -1 && index < this.size()) {
if (this.elements[index] !== value) {
this.elements[index] = value;
}
siftUp(this.elements, this.comparator, index, this.symbols.index);
siftDown(this.elements, this.comparator, index, this.symbols.index);
}
return this;
}
// O(n) or O(log(n)) if indexed
}, {
key: 'remove',
value: function remove(elem) {
return this.removeAt(indexOf(this.elements, elem, this.symbols.index));
}
// O(log(n))
}, {
key: 'removeAt',
value: function removeAt(index) {
if (index > -1 && index < this.size()) {
if (index === this.size() - 1) {
this.elements.pop();
} else {
this.elements[index] = this.elements.pop();
siftUp(this.elements, this.comparator, index, this.symbols.index);
siftDown(this.elements, this.comparator, index, this.symbols.index);
}
return true;
}
return false;
}
}, {
key: 'merge',
value: function merge(heap) {
var result = this.clone();
result.push.apply(result, heap.elements);
return result;
}
}, {
key: 'meld',
value: function meld(heap) {
this.push.apply(this, heap.elements);
return this;
}
// O(n.log(n))
}, {
key: 'sort',
value: function sort() {
var result = this.elements.slice(0);
for (var i = result.length - 1; i > 0; --i) {
var tmp = result[0];
result[0] = result[i];
result[i] = tmp;
siftDown(result, this.comparator, 0, i, this.symbols.index);
}
return result;
}
}, {
key: 'toArray',
value: function toArray() {
return this.elements.slice(0);
}
}], [{
key: 'heapify',
value: function heapify(arr, comp, sym) {
if (comp === undefined) comp = comparator;
if (!Array.isArray(arr)) {
return arr;
}
var pivot = arr.length - 1 >> 1;
if (sym) {
for (var i = arr.length - 1; i > pivot; --i) {
updateIndexAt(arr, i, sym);
}
}
for (var i = pivot; i >= 0; --i) {
siftDown(arr, comp, i, sym);
}
return arr;
}
// O(n.log(n))
}, {
key: 'sort',
value: function sort(arr, comp, opts) {
return new Heapster(arr, comp, opts).sort();
}
// O(1)
}, {
key: 'clean',
value: function clean(elem) {
if (symbols.index) {
delete elem[symbols.index];
}
return elem;
}
}]);
return Heapster;
})();
exports['default'] = Heapster;
module.exports = exports['default'];