Skip to content

Commit cfaff9c

Browse files
author
Isaac Ramirez
committed
- implement MaxPQ ADT
1 parent 374dede commit cfaff9c

File tree

3 files changed

+556
-0
lines changed

3 files changed

+556
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
const MaxPQ = require('./priority-queue-max')
2+
const { StdIn, StdOut } = require('../../libs')
3+
const { Stack, Transaction } = require('../index')
4+
5+
/**
6+
* LowestM
7+
* @classdesc Max Priority Queue Test client.
8+
* @see p. 311
9+
*/
10+
class LowestM {
11+
/**
12+
* Prints the lowest `m` transactions from the StdIn.
13+
* @param {[]} args [m]
14+
* @example <caption>Print the lowest 5 transactions</caption>
15+
* ```sh
16+
* $ node priority-queue-max.client.js 5 < ~/algs4-data/tinyBatch.txt
17+
* Turing 1/11/2002 66.1
18+
* Turing 6/17/1990 644.08
19+
* Dijkstra 9/10/2000 708.95
20+
* Dijkstra 11/18/1995 837.42
21+
* Hoare 8/12/2003 1025.7
22+
* ```
23+
*/
24+
static main (args) {
25+
const m = parseInt(args[0], 10)
26+
const pq = new MaxPQ(m + 1)
27+
28+
StdIn.read()
29+
.on('line', line => {
30+
pq.insert(new Transaction(line.trim()))
31+
32+
if (pq.size() > m) {
33+
pq.delMax()
34+
}
35+
})
36+
.on('close', () => {
37+
const stack = new Stack()
38+
39+
while (!pq.isEmpty()) {
40+
stack.push(pq.delMax())
41+
}
42+
43+
for (const transaction of stack) {
44+
StdOut.println(String(transaction))
45+
}
46+
})
47+
}
48+
}
49+
50+
// Execution
51+
// ==============================
52+
LowestM.main(process.argv.slice(2))
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
const { compare } = require('../../common')
2+
3+
/**
4+
* MaxPQ
5+
* @classdesc Maximum Priority Queue implementation with a binary heap.
6+
* @see p. 309, 315, 316, 318
7+
* @see {@link https://algs4.cs.princeton.edu/code/edu/princeton/cs/algs4/MaxPQ.java.html}
8+
*/
9+
class MaxPQ {
10+
/**
11+
* MaxPQ. Maximum Priority Queue
12+
* @constructor
13+
* @param {number|[*]} [max] Maximum fixed size for the PQ or Array of keys to create the PQ from.
14+
*/
15+
constructor (max) {
16+
/**
17+
* Initial PQ size
18+
*/
19+
this._n = 0
20+
21+
/**
22+
* Heap-Ordered complete binary tree in _pq[1..n] with _pq[0] unused
23+
*/
24+
this._pq = [] // default initialization
25+
26+
if (typeof max === 'number' && Number.isInteger(max) && max > 0) {
27+
this._pq = new Array(max + 1)
28+
} else if (Array.isArray(max)) {
29+
// TODO: initialize from keys in max
30+
}
31+
32+
Object.seal(this)
33+
}
34+
35+
/**
36+
* Compares if key at index `i` is less than key at index `j`.
37+
* @private
38+
* @param {number} i Index of first key
39+
* @param {number} j Index of second key
40+
* @returns {boolean} if key at index `i` is less than key at index`j`
41+
*/
42+
less (i, j) {
43+
return compare(this._pq[i], this._pq[j]) < 0
44+
}
45+
46+
/**
47+
* Exchanges keys at indexes `i` and `j`.
48+
* @private
49+
* @param {number} i Index of first key
50+
* @param {number} j Index of second key
51+
* @returns {void}
52+
*/
53+
exch (i, j) {
54+
const t = this._pq[i]
55+
56+
this._pq[i] = this._pq[j]
57+
this._pq[j] = t
58+
}
59+
60+
/**
61+
* Bottom-up reheapify (maximum).
62+
* Algorithm to fix the heap order when a key becomes
63+
* __greater__ than its parent.
64+
* @private
65+
* @param {number} k Index of the key to _swim_.
66+
* @returns {void}
67+
*/
68+
swim (k) {
69+
// while current index `k` is not the root (k > 1)
70+
// and while the parent node (at k / 2) is lower than
71+
// the current node (at k), exchange both nodes.
72+
while (k > 1 && this.less(Math.floor(k / 2), k)) {
73+
this.exch(Math.floor(k / 2), k)
74+
k = Math.floor(k / 2)
75+
}
76+
}
77+
78+
/**
79+
* Top-down reheapify (maximum).
80+
* Algorithm to fix the heap order when a key becomes
81+
* __smaller__ than a child.
82+
* @private
83+
* @param {number} k Index of the key to _sink_.
84+
* @returns {void}
85+
*/
86+
sink (k) {
87+
// while `k` still having next child
88+
// that is in bounds with the PQ size (_n).
89+
while (2 * k <= this._n) {
90+
// let `j` be the next left child of ´k´ (2 * k)
91+
let j = 2 * k
92+
93+
// if the left child (j) is smaller than the right child (j + 1)
94+
// then choose the right child (j++)
95+
if (j < this._n && this.less(j, j + 1)) {
96+
j++
97+
}
98+
99+
// if parent node (at k) is NOT smaller than
100+
// the child node (at j), then we have found
101+
// its final position
102+
if (!this.less(k, j)) {
103+
break
104+
}
105+
106+
this.exch(k, j)
107+
108+
k = j
109+
}
110+
}
111+
112+
/**
113+
* Returns if the PQ is empty
114+
* @returns {boolean} if the PQ is empty
115+
*/
116+
isEmpty () {
117+
return this._n === 0
118+
}
119+
120+
/**
121+
* Returns the size of the PQ
122+
* @returns {number} the PQ size (total nodes)
123+
*/
124+
size () {
125+
return this._n
126+
}
127+
128+
/**
129+
* Inserts a new key to the PQ and fixes the heap order.
130+
* @param {*} v The Key to be inserted
131+
* @returns {void}
132+
*/
133+
insert (v) {
134+
this._pq[++this._n] = v
135+
this.swim(this._n)
136+
}
137+
138+
/**
139+
* Removes and returns the _maximum_ key in the PQ,
140+
* then it fixes the heap order.
141+
* @returns {*} The maximum Key in the PQ
142+
*/
143+
delMax () {
144+
const max = this._pq[1] // retrieve max Key from top
145+
146+
this.exch(1, this._n--) // exchange with the last item
147+
this._pq[this._n + 1] = undefined // avoid loitering
148+
this.sink(1) // restore heap property
149+
150+
return max
151+
}
152+
153+
/**
154+
* Returns the `maximum` key in the PQ.
155+
* @returns {*} The maximum key in the PQ.
156+
*/
157+
max () {
158+
if (this.isEmpty()) {
159+
throw new ReferenceError('MaxPQ is empty.')
160+
}
161+
return this._pq[1]
162+
}
163+
}
164+
165+
module.exports = MaxPQ

0 commit comments

Comments
 (0)