UNPKG

priority-queue-with-custom-comparator

Version:

Priority queue data structure where you are able to set your own compare function.

139 lines (138 loc) 4.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); class PriorityQueue { /** * * @param options * options.comparator: function used to compare elements; * options.initialElements: elements to be put in priority queue initially in O(n) time */ constructor(options) { this.heap = []; this.comparator = options.comparator; if (options.initialElements) this.buildHeap(options.initialElements); } /** * * @returns size of priority queue in O(1) */ size() { return this.heap.length; } /** * * @returns is priority queue empty in O(1) */ isEmpty() { return this.size() === 0; } /** * * @returns top of priority queue in O(1), if priority queue is empty returns undefined */ peek() { return this.heap[0] ? JSON.parse(JSON.stringify(this.heap[0])) : undefined; } /** * clears priority queue in O(1) */ clear() { this.heap = []; } /** * checks if value exists in priority queue in O(n) */ has(value) { return !!this.heap.find((ele) => ele === value); } /** * * @returns all values of priority queue in O(n) */ values() { return JSON.parse(JSON.stringify(this.heap)); } buildHeap(array) { this.heap = JSON.parse(JSON.stringify(array)); for (let i = Math.floor(array.length / 2) - 1; i >= 0; i--) { this.siftDown(i); } } /** * * @param value element to be added to heap, adds it in O(log n) operations, n is size of heap * @returns size of heap */ push(value) { this.heap.push(value); this.siftUp(); return this.size(); } /** * * @param values elements to be added to heap, adds it in O(k * log n) operations, n is size of heap, k is number of elements added * @returns size of heap */ pushMany(values) { values.forEach((value) => { this.push(value); }); return this.size(); } /** * * @returns top of priority queue and removes it from priority queue in O(log n), if priority queue is empty returns undefined */ pop() { if (this.isEmpty()) { return undefined; } const returnValue = this.peek(); const lastIndexOfHeapArray = this.size() - 1; if (lastIndexOfHeapArray > 0) { this.swap(0, lastIndexOfHeapArray); } this.heap.pop(); this.siftDown(); return returnValue; } getParent(index) { return ((index + 1) >>> 1) - 1; } getLeftChild(index) { return (index << 1) + 1; } getRightChild(index) { return (index + 1) << 1; } compareByIndex(i, j) { return this.comparator(this.heap[i], this.heap[j]); } swap(i, j) { [this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]; } siftUp() { let node = this.size() - 1; while (node > 0 && this.compareByIndex(node, this.getParent(node))) { const parentNode = this.getParent(node); this.swap(node, parentNode); node = parentNode; } } siftDown(node = 0) { let leftChild = this.getLeftChild(node); let rightChild = this.getRightChild(node); while ((leftChild < this.size() && this.compareByIndex(leftChild, node)) || (rightChild < this.size() && this.compareByIndex(rightChild, node))) { const maxChild = rightChild < this.size() && this.compareByIndex(rightChild, leftChild) ? rightChild : leftChild; this.swap(node, maxChild); node = maxChild; leftChild = this.getLeftChild(node); rightChild = this.getRightChild(node); } } } exports.default = PriorityQueue;