125 lines
4.4 KiB
JavaScript
125 lines
4.4 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const index_1 = require("../ContainerBase/index");
|
|
class PriorityQueue extends index_1.Base {
|
|
/**
|
|
* @description PriorityQueue's constructor.
|
|
* @param container Initialize container, must have a forEach function.
|
|
* @param cmp Compare function.
|
|
* @param copy When the container is an array, you can choose to directly operate on the original object of
|
|
* the array or perform a shallow copy. The default is shallow copy.
|
|
*/
|
|
constructor(container = [], cmp = (x, y) => {
|
|
if (x > y)
|
|
return -1;
|
|
if (x < y)
|
|
return 1;
|
|
return 0;
|
|
}, copy = true) {
|
|
super();
|
|
this.cmp = cmp;
|
|
if (Array.isArray(container)) {
|
|
this.priorityQueue = copy ? [...container] : container;
|
|
}
|
|
else {
|
|
this.priorityQueue = [];
|
|
container.forEach(element => this.priorityQueue.push(element));
|
|
}
|
|
this.length = this.priorityQueue.length;
|
|
for (let parent = (this.length - 1) >> 1; parent >= 0; --parent) {
|
|
let curParent = parent;
|
|
let curChild = (curParent << 1) | 1;
|
|
while (curChild < this.length) {
|
|
const left = curChild;
|
|
const right = left + 1;
|
|
let minChild = left;
|
|
if (right < this.length &&
|
|
this.cmp(this.priorityQueue[left], this.priorityQueue[right]) > 0) {
|
|
minChild = right;
|
|
}
|
|
if (this.cmp(this.priorityQueue[curParent], this.priorityQueue[minChild]) <= 0)
|
|
break;
|
|
[this.priorityQueue[curParent], this.priorityQueue[minChild]] =
|
|
[this.priorityQueue[minChild], this.priorityQueue[curParent]];
|
|
curParent = minChild;
|
|
curChild = (curParent << 1) | 1;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* @description Adjusting parent's children to suit the nature of the heap.
|
|
* @param parent Parent's index.
|
|
* @private
|
|
*/
|
|
adjust(parent) {
|
|
const left = (parent << 1) | 1;
|
|
const right = (parent << 1) + 2;
|
|
if (left < this.length &&
|
|
this.cmp(this.priorityQueue[parent], this.priorityQueue[left]) > 0) {
|
|
[this.priorityQueue[parent], this.priorityQueue[left]] =
|
|
[this.priorityQueue[left], this.priorityQueue[parent]];
|
|
}
|
|
if (right < this.length &&
|
|
this.cmp(this.priorityQueue[parent], this.priorityQueue[right]) > 0) {
|
|
[this.priorityQueue[parent], this.priorityQueue[right]] =
|
|
[this.priorityQueue[right], this.priorityQueue[parent]];
|
|
}
|
|
}
|
|
clear() {
|
|
this.length = 0;
|
|
this.priorityQueue.length = 0;
|
|
}
|
|
/**
|
|
* @description Push element into a container in order.
|
|
* @param element The element you want to push.
|
|
*/
|
|
push(element) {
|
|
this.priorityQueue.push(element);
|
|
this.length += 1;
|
|
if (this.length === 1)
|
|
return;
|
|
let curNode = this.length - 1;
|
|
while (curNode > 0) {
|
|
const parent = (curNode - 1) >> 1;
|
|
if (this.cmp(this.priorityQueue[parent], element) <= 0)
|
|
break;
|
|
this.adjust(parent);
|
|
curNode = parent;
|
|
}
|
|
}
|
|
/**
|
|
* @description Removes the top element.
|
|
*/
|
|
pop() {
|
|
if (!this.length)
|
|
return;
|
|
const last = this.priorityQueue[this.length - 1];
|
|
this.length -= 1;
|
|
let parent = 0;
|
|
while (parent < this.length) {
|
|
const left = (parent << 1) | 1;
|
|
const right = (parent << 1) + 2;
|
|
if (left >= this.length)
|
|
break;
|
|
let minChild = left;
|
|
if (right < this.length &&
|
|
this.cmp(this.priorityQueue[left], this.priorityQueue[right]) > 0) {
|
|
minChild = right;
|
|
}
|
|
if (this.cmp(this.priorityQueue[minChild], last) >= 0)
|
|
break;
|
|
this.priorityQueue[parent] = this.priorityQueue[minChild];
|
|
parent = minChild;
|
|
}
|
|
this.priorityQueue[parent] = last;
|
|
this.priorityQueue.pop();
|
|
}
|
|
/**
|
|
* @description Accesses the top element.
|
|
*/
|
|
top() {
|
|
return this.priorityQueue[0];
|
|
}
|
|
}
|
|
exports.default = PriorityQueue;
|