@thermopylae/lib.cache
Version:
131 lines (130 loc) • 3.72 kB
JavaScript
const HEAP_NODE_IDX_SYM = Symbol('HEAP_NODE_INDEX_SYMBOL');
class Heap {
comparator;
nodes;
constructor(comparator) {
this.comparator = comparator;
this.nodes = [];
}
push(node) {
this.pushNodeIntoInternalCollection(node);
this.propagateUp(node);
}
peek() {
return this.root;
}
pop() {
const lastChildNode = this.nodes.pop();
let nodeToBeReturned;
if (this.nodes.length) {
nodeToBeReturned = this.root;
this.root = lastChildNode;
this.propagateDown(lastChildNode);
}
else {
nodeToBeReturned = lastChildNode;
}
if (nodeToBeReturned) {
Heap.detachMetadata(nodeToBeReturned);
}
return nodeToBeReturned;
}
delete(node) {
const { fartestRightNode } = this;
if (node === fartestRightNode) {
this.nodes.length -= 1;
}
else {
this.swap(node, fartestRightNode);
this.nodes.length -= 1;
if (this.propagateDown(fartestRightNode) === fartestRightNode) {
this.propagateUp(fartestRightNode);
}
}
Heap.detachMetadata(node);
}
heapifyUpdatedNode(node) {
if (this.propagateDown(node) === node) {
this.propagateUp(node);
}
}
clear() {
this.nodes.length = 0;
}
get size() {
return this.nodes.length;
}
static isPartOfHeap(node) {
return node[HEAP_NODE_IDX_SYM] != null;
}
get root() {
return this.nodes[0];
}
set root(node) {
this.nodes[0] = node;
node[HEAP_NODE_IDX_SYM] = 0;
}
get fartestRightNode() {
return this.nodes[this.nodes.length - 1];
}
propagateUp(node) {
let parent;
while (Heap.isNotRoot(node)) {
parent = this.parent(node);
if (this.comparator(node, parent) < 0) {
this.swap(node, parent);
}
else {
return;
}
}
}
propagateDown(node) {
let leftChild = this.leftChild(node);
let rightChild;
let largest;
while (leftChild) {
largest = node;
if (this.comparator(leftChild, largest) < 0) {
largest = leftChild;
}
rightChild = this.rightSibling(leftChild);
if (rightChild && this.comparator(rightChild, largest) < 0) {
largest = rightChild;
}
if (largest === node) {
return node;
}
this.swap(node, largest);
leftChild = this.leftChild(node);
}
return node;
}
swap(first, second) {
this.nodes[first[HEAP_NODE_IDX_SYM]] = second;
this.nodes[second[HEAP_NODE_IDX_SYM]] = first;
const aux = first[HEAP_NODE_IDX_SYM];
first[HEAP_NODE_IDX_SYM] = second[HEAP_NODE_IDX_SYM];
second[HEAP_NODE_IDX_SYM] = aux;
}
pushNodeIntoInternalCollection(node) {
this.nodes.push(node);
node[HEAP_NODE_IDX_SYM] = this.nodes.length - 1;
}
leftChild(parentNode) {
return this.nodes[parentNode[HEAP_NODE_IDX_SYM] * 2 + 1];
}
rightSibling(childNode) {
return this.nodes[childNode[HEAP_NODE_IDX_SYM] + 1];
}
parent(childNode) {
return this.nodes[(childNode[HEAP_NODE_IDX_SYM] - 1) >> 1];
}
static isNotRoot(node) {
return node[HEAP_NODE_IDX_SYM] !== 0;
}
static detachMetadata(node) {
node[HEAP_NODE_IDX_SYM] = undefined;
}
}
export { Heap, HEAP_NODE_IDX_SYM };