-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMaxPQ.hpp
211 lines (187 loc) · 6.07 KB
/
MaxPQ.hpp
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#ifndef ALGORITHMS_MAXPQ_HPP
#define ALGORITHMS_MAXPQ_HPP
#include <span> // std::span
#include <array> // std::array
#include <vector> // std::vector
#include "Comparable.hpp" // includes Comparable concept used as a constraint
#include <cassert> // std::assert
#include <boost/lexical_cast.hpp> // boost::lexical_cast
using namespace std;
/**
* The {@code MaxPQ} class represents a priority queue of generic keys.
* It supports the usual insert and delete-the-maximum
* operations, along with methods for peeking at the maximum key,
* testing if the priority queue is empty, and iterating through
* the keys.
*
* This implementation uses a binary heap.
* The insert and delete-the-maximum operations take
* Θ(log(n)) amortized time, where n is the number
* of elements in the priority queue. This is an amortized bound
* (and not a worst-case bound) because of array resizing operations.
* The min, size, and is-empty operations take
* Θ(1) time in the worst case.
* Construction takes time proportional to the specified capacity or the
* number of items used to initialize the data structure.
*
* @author Benjamin Chan
*
* Adapted from Algorithms, 4th edition, {@authors Robert Sedgewick and Kevin Wayne}
* and their booksite https://algs4.cs.princeton.edu/
*
* The Java program from which this C++ code was adapted from is found at
* https://algs4.cs.princeton.edu/24pq/MaxPQ.java.html.
*
* @param <T> the generic type of key on this priority queue
*/
template<typename T> requires Comparable<T>
class MaxPQ {
public:
/**
* Initializes an empty priority queue.
*/
MaxPQ() {
this->n = 0;
}
/**
* Initializes a priority queue from the vector of keys.
* Takes time proportional to the number of keys, using sink-based heap construction.
*
* @param keys, the vector of keys
*/
explicit MaxPQ(vector<T> keys) {
n = keys.size();
pq = vector<T>(n + 1);
for (int i = 0; i < n; i++)
pq[i + 1] = keys[i];
for (int k = n / 2; k >= 1; k--)
sink(k);
}
/**
* Returns true if this priority queue is empty.
*
* @return {@code true} if this priority queue is empty;
* {@code false} otherwise
*/
bool isEmpty() {
return n == 0;
}
/**
* Returns the number of keys on this priority queue.
*
* @return the number of keys on this priority queue
*/
int size() {
return n;
}
/**
* Returns a largest key on this priority queue.
*
* @return a largest key on this priority queue
* @throws NoSuchElementException if this priority queue is empty
*/
T max() {
try {
if (isEmpty()) throw NoSuchElementException();
return pq[1];
}
catch (NoSuchElementException &e) {
std::cout << "NoSuchElementException encountered: ";
std::cout << e.what() << std::endl;
}
}
/**
* Adds a new key to this priority queue.
*
* @param x the new key to add to this priority queue
*/
void insert(T x) {
// add x, and percolate it up to maintain heap invariant
pq.push_back(x);
swim(n);
}
/**
* Removes and returns a largest key on this priority queue.
*
* @return a largest key on this priority queue
* @throws NoSuchElementException if this priority queue is empty
*/
T delMax() {
try {
if (isEmpty()) throw NoSuchElementException();
T max = pq[1];
exch(1, n--);
sink(1);
pq.erase(pq.begin() + n + 1); // to avoid loitering and help with garbage collection
return max;
}
catch (NoSuchElementException &e) {
std::cout << "NoSuchElementException encountered: ";
std::cout << e.what() << std::endl;
}
}
/**
* Returns a string representation of this priority queue.
*
* @return the sequence of items in descending order, separated by spaces
*/
[[nodiscard]] std::string toString() const;
private:
vector<T> pq; // store items at indices 1 to n
int n{}; // number of items on priority queue
/**
* @def the NoSuchElementException if there are no items in the priority queue after
* using the max(), methods
*/
struct NoSuchElementException : public std::exception {
const char *what() {
return "Priority Queue Underflow";
}
};
/***************************************************************************
* Helper functions to restore the heap invariant.
***************************************************************************/
void swim(int k) {
while (k > 1 && pq[k / 2] < k) {
exch(k, k / 2);
k = k / 2;
}
}
void sink(int k) {
while (2 * k <= n) {
int j = 2 * k;
if (j < n && pq[j] < pq[j + 1]) j++;
if (pq[k] >= pq[j]) break;
exch(k, j);
k = j;
}
}
/***************************************************************************
* Helper functions for compares and swaps.
***************************************************************************/
void exch(int i, int j) {
T swap = pq[i];
pq[i] = pq[j];
pq[j] = swap;
}
};
template<typename T>
requires Comparable<T>
std::string MaxPQ<T>::toString() const {
std::stringstream ss;
MaxPQ<T> copy{this->pq};
while (!copy.isEmpty()) {
ss << boost::lexical_cast<std::string>(copy.delMax()) << " ";
}
ss << endl;
return ss.str();
}
/// Overloads the "<<" operator for a bag
template<typename T>
std::ostream &operator<<(std::ostream &os, const MaxPQ<T> &maxPQ) {
return os << maxPQ.toString();
}
/// Uses type deduction for one of the constructors
template<typename T> requires Comparable<T>
MaxPQ(vector<T>) -> MaxPQ<T>;
#endif //ALGORITHMS_MAXPQ_HPP