| 'use strict'; |
| |
| const { |
| Array, |
| } = primordials; |
| |
| // The PriorityQueue is a basic implementation of a binary heap that accepts |
| // a custom sorting function via its constructor. This function is passed |
| // the two nodes to compare, similar to the native Array#sort. Crucially |
| // this enables priority queues that are based on a comparison of more than |
| // just a single criteria. |
| |
| module.exports = class PriorityQueue { |
| #compare = (a, b) => a - b; |
| #heap = new Array(64); |
| #setPosition; |
| #size = 0; |
| |
| constructor(comparator, setPosition) { |
| if (comparator !== undefined) |
| this.#compare = comparator; |
| if (setPosition !== undefined) |
| this.#setPosition = setPosition; |
| } |
| |
| insert(value) { |
| const heap = this.#heap; |
| const pos = ++this.#size; |
| heap[pos] = value; |
| |
| if (heap.length === pos) |
| heap.length *= 2; |
| |
| this.percolateUp(pos); |
| } |
| |
| peek() { |
| return this.#heap[1]; |
| } |
| |
| peekBottom() { |
| return this.#heap[this.#size]; |
| } |
| |
| percolateDown(pos) { |
| const compare = this.#compare; |
| const setPosition = this.#setPosition; |
| const heap = this.#heap; |
| const size = this.#size; |
| const hsize = size >> 1; |
| const item = heap[pos]; |
| |
| while (pos <= hsize) { |
| let child = pos << 1; |
| const nextChild = child + 1; |
| let childItem = heap[child]; |
| |
| if (nextChild <= size && compare(heap[nextChild], childItem) < 0) { |
| child = nextChild; |
| childItem = heap[nextChild]; |
| } |
| |
| if (compare(item, childItem) <= 0) break; |
| |
| if (setPosition !== undefined) |
| setPosition(childItem, pos); |
| |
| heap[pos] = childItem; |
| pos = child; |
| } |
| |
| heap[pos] = item; |
| if (setPosition !== undefined) |
| setPosition(item, pos); |
| } |
| |
| percolateUp(pos) { |
| const heap = this.#heap; |
| const compare = this.#compare; |
| const setPosition = this.#setPosition; |
| const item = heap[pos]; |
| |
| while (pos > 1) { |
| const parent = pos >> 1; |
| const parentItem = heap[parent]; |
| if (compare(parentItem, item) <= 0) |
| break; |
| heap[pos] = parentItem; |
| if (setPosition !== undefined) |
| setPosition(parentItem, pos); |
| pos = parent; |
| } |
| |
| heap[pos] = item; |
| if (setPosition !== undefined) |
| setPosition(item, pos); |
| } |
| |
| removeAt(pos) { |
| const heap = this.#heap; |
| let size = this.#size; |
| heap[pos] = heap[size]; |
| heap[size] = undefined; |
| size = --this.#size; |
| |
| if (size > 0 && pos <= size) { |
| if (pos > 1 && this.#compare(heap[pos >> 1], heap[pos]) > 0) |
| this.percolateUp(pos); |
| else |
| this.percolateDown(pos); |
| } |
| } |
| |
| shift() { |
| const heap = this.#heap; |
| const value = heap[1]; |
| if (value === undefined) |
| return; |
| |
| this.removeAt(1); |
| |
| return value; |
| } |
| }; |