-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmin-priority-queue.js
165 lines (144 loc) · 3.87 KB
/
min-priority-queue.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
const { compare } = require('../../common')
/**
* MinPQ
* @classdesc Minimum Priority Queue implementation with a binary heap.
* @see p. 309, 315, 316, 318
* @see {@link https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/MinPQ.java.html}
*/
class MinPQ {
/**
* MinPQ. Minimum Priority Queue
* @constructor
* @param {number|[*]} [max] Maximum fixed size for the PQ or Array of keys to create the PQ from.
*/
constructor (max) {
/**
* Initial PQ size
*/
this._n = 0
/**
* Heap-Ordered complete binary tree in _pq[1..n] with _pq[0] unused
*/
this._pq = [] // default initialization
if (typeof max === 'number' && Number.isInteger(max) && max > 0) {
this._pq = new Array(max + 1)
} else if (Array.isArray(max)) {
// TODO: initialize from keys in max
}
Object.seal(this)
}
/**
* Compares if key at index `i` is greater than key at index `j`.
* @private
* @param {number} i Index of first key
* @param {number} j Index of second key
* @returns {boolean} if key at index `i` is greater than key at index`j`
*/
greater (i, j) {
return compare(this._pq[i], this._pq[j]) > 0
}
/**
* Exchanges keys at indexes `i` and `j`.
* @private
* @param {number} i Index of first key
* @param {number} j Index of second key
* @returns {void}
*/
exch (i, j) {
const t = this._pq[i]
this._pq[i] = this._pq[j]
this._pq[j] = t
}
/**
* Bottom-up reheapify (minimum).
* Algorithm to fix the heap order when a key becomes
* __smaller__ than its parent.
* @private
* @param {number} k Index of the key to _swim_.
* @returns {void}
*/
swim (k) {
// while current index `k` is not the root (k > 1)
// and while the parent node (at k / 2) is greater than
// the current node (at k), exchange both nodes.
while (k > 1 && this.greater(Math.floor(k / 2), k)) {
this.exch(Math.floor(k / 2), k)
k = Math.floor(k / 2)
}
}
/**
* Top-down reheapify (minimum).
* Algorithm to fix the heap order when a key becomes
* __greater__ than a child.
* @private
* @param {number} k Index of the key to _sink_.
* @returns {void}
*/
sink (k) {
// while `k` still having next child
// that is in bounds with the PQ size (_n).
while (2 * k <= this._n) {
// let `j` be the next left child of ´k´ (2 * k)
let j = 2 * k
// if the left child (j) is greater than the right child (j + 1)
// then choose the right child (j++)
if (j < this._n && this.greater(j, j + 1)) {
j++
}
// if parent node (at k) is NOT greater than
// the child node (at j), then we have found
// its final position
if (!this.greater(k, j)) {
break
}
this.exch(k, j)
k = j
}
}
/**
* Returns if the PQ is empty
* @returns {boolean} if the PQ is empty
*/
isEmpty () {
return this._n === 0
}
/**
* Returns the size of the PQ
* @returns {number} the PQ size (total nodes)
*/
size () {
return this._n
}
/**
* Inserts a new key to the PQ and fixes the heap order.
* @param {*} v The Key to be inserted
* @returns {void}
*/
insert (v) {
this._pq[++this._n] = v
this.swim(this._n)
}
/**
* Removes and returns the _minimum_ key in the PQ,
* then it fixes the heap order.
* @returns {*} The minimum Key in the PQ
*/
delMin () {
const min = this._pq[1] // retrieve min Key from top
this.exch(1, this._n--) // exchange with the last item
this._pq[this._n + 1] = undefined // avoid loitering
this.sink(1) // restore heap property
return min
}
/**
* Returns the `minimum` key in the PQ.
* @returns {*} The minimum key in the PQ.
*/
min () {
if (this.isEmpty()) {
throw new ReferenceError('MinPQ is empty.')
}
return this._pq[1]
}
}
module.exports = MinPQ