itns-sidechain/lib/utils/heap.js

245 lines
3.6 KiB
JavaScript
Raw Normal View History

2017-02-26 12:52:39 -08:00
/*!
* heap.js - heap object for bcoin
2017-02-26 21:45:16 -08:00
* Copyright (c) 2017, Christopher Jeffrey (MIT License).
2017-02-26 12:52:39 -08:00
* https://github.com/bcoin-org/bcoin
*/
'use strict';
2017-06-29 20:54:07 -07:00
const assert = require('assert');
2017-02-26 12:52:39 -08:00
/**
2017-02-26 21:45:16 -08:00
* Binary Heap
2017-02-26 12:52:39 -08:00
* @alias module:utils.Heap
*/
class Heap {
/**
* Create a binary heap.
* @constructor
* @param {Function?} compare
*/
2017-02-26 12:52:39 -08:00
constructor(compare) {
this.compare = comparator;
this.items = [];
2017-02-26 21:45:16 -08:00
if (compare)
this.set(compare);
}
2017-02-26 12:52:39 -08:00
/**
* Initialize and sort heap.
*/
2017-02-26 12:52:39 -08:00
init() {
const n = this.items.length;
2017-02-26 12:52:39 -08:00
if (n <= 1)
return;
2017-02-26 12:52:39 -08:00
for (let i = (n / 2 | 0) - 1; i >= 0; i--)
this.down(i, n);
}
2017-02-26 12:52:39 -08:00
/**
* Get heap size.
* @returns {Number}
*/
2017-02-26 12:52:39 -08:00
size() {
return this.items.length;
}
2017-02-26 12:52:39 -08:00
/**
* Set comparator.
* @param {Function} compare
*/
2017-02-26 12:52:39 -08:00
set(compare) {
assert(typeof compare === 'function',
'Comparator must be a function.');
this.compare = compare;
}
2017-02-26 12:52:39 -08:00
/**
* Push item onto heap.
* @param {Object} item
* @returns {Number}
*/
2017-02-26 12:52:39 -08:00
insert(item) {
this.items.push(item);
this.up(this.items.length - 1);
return this.items.length;
}
2017-02-26 12:52:39 -08:00
/**
* Pop next item off of heap.
* @param {Object} item
* @returns {Object}
*/
2017-02-26 12:52:39 -08:00
shift() {
if (this.items.length === 0)
return null;
2017-02-26 12:52:39 -08:00
const n = this.items.length - 1;
2017-02-26 12:52:39 -08:00
this.swap(0, n);
this.down(0, n);
2017-02-26 12:52:39 -08:00
return this.items.pop();
}
2017-02-26 12:52:39 -08:00
/**
* Remove item from heap.
* @param {Number} i
* @returns {Object}
*/
2017-02-26 12:52:39 -08:00
remove(i) {
if (this.items.length === 0)
return null;
2017-02-26 12:52:39 -08:00
const n = this.items.length - 1;
2017-02-26 21:45:16 -08:00
if (i < 0 || i > n)
return null;
2017-02-26 12:52:39 -08:00
if (n !== i) {
this.swap(i, n);
this.down(i, n);
this.up(i);
}
2017-02-26 12:52:39 -08:00
return this.items.pop();
}
2017-02-26 12:52:39 -08:00
/**
* Swap indicies.
* @private
* @param {Number} a
* @param {Number} b
*/
swap(a, b) {
const x = this.items[a];
const y = this.items[b];
this.items[a] = y;
this.items[b] = x;
}
2017-02-26 12:52:39 -08:00
/**
* Compare indicies.
* @private
* @param {Number} i
* @param {Number} j
* @returns {Boolean}
*/
2017-02-26 12:52:39 -08:00
less(i, j) {
return this.compare(this.items[i], this.items[j]) < 0;
}
2017-02-26 12:52:39 -08:00
/**
* Bubble item down.
* @private
* @param {Number} i
* @param {Number} n
*/
2017-02-26 12:52:39 -08:00
down(i, n) {
for (;;) {
const l = 2 * i + 1;
2017-02-26 12:52:39 -08:00
assert(l >= 0);
2017-02-26 12:52:39 -08:00
if (l < 0 || l >= n)
break;
2017-02-26 12:52:39 -08:00
let j = l;
const r = l + 1;
2017-02-26 12:52:39 -08:00
if (r < n && !this.less(l, r))
j = r;
2017-02-26 12:52:39 -08:00
if (!this.less(j, i))
break;
2017-02-26 12:52:39 -08:00
this.swap(i, j);
i = j;
}
2017-02-26 12:52:39 -08:00
}
/**
* Bubble item up.
* @private
* @param {Number} i
*/
2017-02-26 12:52:39 -08:00
up(i) {
for (;;) {
const j = (i - 1) / 2 | 0;
2017-02-26 12:52:39 -08:00
assert(j >= 0);
2017-02-26 12:52:39 -08:00
if (j < 0 || j === i)
break;
2017-02-26 12:52:39 -08:00
if (!this.less(i, j))
break;
2017-02-26 12:52:39 -08:00
this.swap(j, i);
i = j;
}
2017-02-26 12:52:39 -08:00
}
/**
* Convert heap to sorted array.
* @returns {Object[]}
*/
2017-02-26 12:52:39 -08:00
toArray() {
const heap = new Heap();
const result = [];
2017-02-26 12:52:39 -08:00
heap.compare = this.compare;
heap.items = this.items.slice();
2017-02-26 12:52:39 -08:00
while (heap.size() > 0)
result.push(heap.shift());
2017-02-26 12:52:39 -08:00
return result;
}
2017-02-26 12:52:39 -08:00
/**
* Instantiate heap from array and comparator.
* @param {Function} compare
* @param {Object[]} items
* @returns {Heap}
*/
static fromArray(compare, items) {
const heap = new Heap();
heap.set(compare);
heap.items = items;
heap.init();
return heap;
}
}
2017-02-26 12:52:39 -08:00
2017-02-26 21:45:16 -08:00
/*
* Helpers
*/
function comparator(a, b) {
throw new Error('No heap comparator set.');
}
2017-02-26 12:52:39 -08:00
/*
* Expose
*/
module.exports = Heap;