dagre-d3-es
Version:
<p align="center"> <a href="https://tbo47.github.io/" ><img src="https://img.shields.io/badge/created_by-tbo47-blue.svg" alt="Created by tbo47"></a> <a href="https://www.npmjs.com/dagre-d3-es"><img src="https://img.shields.io/npm/v/dagre-d3-es.svg?log
180 lines (178 loc) • 4.83 kB
JavaScript
export { PriorityQueue };
/**
* A min-priority queue data structure. This algorithm is derived from Cormen,
* et al., "Introduction to Algorithms". The basic idea of a min-priority
* queue is that you can efficiently (in O(1) time) get the smallest key in
* the queue. Adding and removing elements takes O(log n) time. A key can
* have its priority decreased in O(log n) time.
*/
class PriorityQueue {
constructor() {
/**
* @private
* @type {Array<{key: string, priority: number}>}
*/
this._arr = [];
/**
* @private
* @type {Record<string, number>}
*/
this._keyIndices = {};
}
/**
* @returns {number} the number of elements in the queue.
* @remarks Takes `O(1)` time.
*/
size() {
return this._arr.length;
}
/**
* @returns {string[]} the keys that are in the queue.
* @remarks Takes `O(n)` time.
*/
keys() {
return this._arr.map(function (x) {
return x.key;
});
}
/**
* @param {Object} key - The key to check for presence in the queue.
* @returns {boolean} `true` if **key** is in the queue and `false` if not.
*/
has(key) {
return Object.prototype.hasOwnProperty.call(this._keyIndices, key);
}
/**
* @param {Object} key - The key to get the priority for.
* @returns {number | undefined} the priority for **key**.
* If **key** is not present in the queue then this function returns `undefined`.
* @remarks Takes `O(1)` time.
*/
priority(key) {
var index = this._keyIndices[key];
if (index !== undefined) {
return this._arr[index].priority;
}
}
/**
* @returns {string} the key for the minimum element in this queue.
* @throws {Error} if the queue is empty.
* @remarks Takes `O(1)` time.
*/
min() {
if (this.size() === 0) {
throw new Error('Queue underflow');
}
return this._arr[0].key;
}
/**
* Inserts a new key into the priority queue.
*
* @remarks Takes `O(n)` time.
*
* @param {Object} key the key to add. This will be coerced to a `string`.
* @param {Number} priority the initial priority for the key
* @returns {boolean} `true` if the key was added and `false` if it was already
* present in the queue.
*/
add(key, priority) {
var keyIndices = this._keyIndices;
key = String(key);
if (!Object.prototype.hasOwnProperty.call(keyIndices, key)) {
var arr = this._arr;
var index = arr.length;
keyIndices[key] = index;
arr.push({ key: key, priority: priority });
this._decrease(index);
return true;
}
return false;
}
/**
* Removes and returns the smallest key in the queue.
* @returns {string} the key with the smallest priority
* @remarks Takes `O(log n)` time.
*/
removeMin() {
this._swap(0, this._arr.length - 1);
var min = this._arr.pop();
delete this._keyIndices[min.key];
this._heapify(0);
return min.key;
}
/**
* Decreases the priority for **key** to **priority**.
*
* @param {Object} key the key for which to raise priority
* @param {Number} priority the new priority for the key
* @throws {Error} if the new priority is greater than the previous priority.
*/
decrease(key, priority) {
var index = this._keyIndices[key];
if (priority > this._arr[index].priority) {
throw new Error(
'New priority is greater than current priority. ' +
'Key: ' +
key +
' Old: ' +
this._arr[index].priority +
' New: ' +
priority,
);
}
this._arr[index].priority = priority;
this._decrease(index);
}
/**
* @param {number} i - Lower index.
* @private
*/
_heapify(i) {
var arr = this._arr;
var l = 2 * i;
var r = l + 1;
var largest = i;
if (l < arr.length) {
largest = arr[l].priority < arr[largest].priority ? l : largest;
if (r < arr.length) {
largest = arr[r].priority < arr[largest].priority ? r : largest;
}
if (largest !== i) {
this._swap(i, largest);
this._heapify(largest);
}
}
}
/**
* @param {number} index - Index to decrease.
* @private
*/
_decrease(index) {
var arr = this._arr;
var priority = arr[index].priority;
var parent;
while (index !== 0) {
parent = index >> 1;
if (arr[parent].priority < priority) {
break;
}
this._swap(index, parent);
index = parent;
}
}
/**
* @param {number} i - First index
* @param {number} j - Second index
* @private
*/
_swap(i, j) {
var arr = this._arr;
var keyIndices = this._keyIndices;
var origArrI = arr[i];
var origArrJ = arr[j];
arr[i] = origArrJ;
arr[j] = origArrI;
keyIndices[origArrJ.key] = i;
keyIndices[origArrI.key] = j;
}
}