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
JavaScript
"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;