-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathBinarySearchST.h
308 lines (275 loc) · 9.94 KB
/
BinarySearchST.h
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
#ifndef CH3_BINARYSEARCHST_H
#define CH3_BINARYSEARCHST_H
#include <vector>
#include <stdexcept>
using std::vector;
using std::runtime_error;
/**
* The {@code BST} class represents an ordered symbol table of generic
* key-value pairs.
* It supports the usual <em>put</em>, <em>get</em>, <em>contains</em>,
* <em>delete</em>, <em>size</em>, and <em>is-empty</em> methods.
* It also provides ordered methods for finding the <em>minimum</em>,
* <em>maximum</em>, <em>floor</em>, <em>select</em>, and <em>ceiling</em>.
* It also provides a <em>keys</em> method for iterating over all of the keys.
* A symbol table implements the <em>associative array</em> abstraction:
* when associating a value with a key that is already in the symbol table,
* the convention is to replace the old value with the new value.
* Unlike {@link java.util.Map}, this class uses the convention that
* values cannot be {@code null}—setting the
* value associated with a key to {@code null} is equivalent to deleting the key
* from the symbol table.
* <p>
* This implementation uses a sorted array. It requires that
* the key type implements the {@code Comparable} interface and calls the
* {@code compareTo()} and method to compare two keys. It does not call either
* {@code equals()} or {@code hashCode()}.
* The <em>put</em> and <em>remove</em> operations each take linear time in
* the worst case; the <em>contains</em>, <em>ceiling</em>, <em>floor</em>,
* and <em>rank</em> operations take logarithmic time; the <em>size</em>,
* <em>is-empty</em>, <em>minimum</em>, <em>maximum</em>, and <em>select</em>
* operations take constant time. Construction takes constant time.
* <p>
* For additional documentation, see <a href="https://algs4.cs.princeton.edu/31elementary">Section 3.1</a> of
* <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
* For other implementations, see {@link ST}, {@link BST},
* {@link SequentialSearchST}, {@link RedBlackBST},
* {@link SeparateChainingHashST}, and {@link LinearProbingHashST},
* <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
*/
template<typename Key, typename Value>
class BinarySearchST {
public:
/**
* Initializes an empty symbol table with the specified initial capacity.
* @param capacity the maximum capacity
*/
BinarySearchST(int capacity) : keys(capacity), vals(capacity) {}
/**
* Initializes an empty symbol table.
*/
BinarySearchST() : BinarySearchST(INIT_CAPACITY) {}
/**
* Returns the number of key-value pairs in this symbol table.
*
* @return the number of key-value pairs in this symbol table
*/
int size() {
return n;
}
/**
* Returns true if this symbol table is empty.
*
* @return {@code true} if this symbol table is empty;
* {@code false} otherwise
*/
bool isEmpty() {
return size() == 0;
}
/**
* Returns the number of keys in this symbol table strictly less than {@code key}.
*
* @param key the key
* @return the number of keys in the symbol table strictly less than {@code key}
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
int rank(Key key) {
int lo = 0, hi = n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (key < keys[mid]) hi = mid - 1;
else if (key > keys[mid]) lo = mid + 1;
else return mid;
}
return lo;
}
/**
* Returns the value associated with the given key in this symbol table.
*
* @param key the key
* @return the value associated with the given key if the key is in the symbol table
* and {@code null} if the key is not in the symbol table
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
Value get(Key key) {
int i = rank(key);
if (i < n && keys[i] == key) return vals[i];
throw runtime_error("can not find key");
}
/**
* Does this symbol table contain the given key?
*
* @param key the key
* @return {@code true} if this symbol table contains {@code key} and
* {@code false} otherwise
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
bool contains(Key key) {
int i = rank(key);
if (i < n && keys[i] == key) return true;
else return false;
}
/**
* Inserts the specified key-value pair into the symbol table, overwriting the old
* value with the new value if the symbol table already contains the specified key.
* Deletes the specified key (and its associated value) from this symbol table
* if the specified value is {@code null}.
*
* @param key the key
* @param val the value
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
void put(Key key, Value val) {
int i = rank(key);
// key is already in table
if (i < n && keys[i] == key) {
vals[i] = val;
return;
}
// insert new key-value pair
if (n == keys.size()) resize(2 * keys.size());
for (int j = n; j > i; j--) {
keys[j] = keys[j - 1];
vals[j] = vals[j - 1];
}
keys[i] = key;
vals[i] = val;
n++;
}
/**
* Removes the specified key and associated value from this symbol table
* (if the key is in the symbol table).
*
* @param key the key
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
void delete_op(Key key) {
if (isEmpty()) return;
// compute rank
int i = rank(key);
// key not in table
if (i == n || keys[i] != key) {
return;
}
for (int j = i; j < n - 1; j++) {
keys[j] = keys[j + 1];
vals[j] = vals[j + 1];
}
n--;
// resize if 1/4 full
if (n > 0 && n == keys.size() / 4) resize(keys.size() / 2);
}
/**
* Removes the smallest key and associated value from this symbol table.
*
* @throws NoSuchElementException if the symbol table is empty
*/
void deleteMin() {
if (isEmpty()) throw runtime_error("Symbol table underflow error");
delete_op(min());
}
/**
* Removes the largest key and associated value from this symbol table.
*
* @throws NoSuchElementException if the symbol table is empty
*/
void deleteMax() {
if (isEmpty()) throw runtime_error("Symbol table underflow error");
delete (max());
}
/***************************************************************************
* Ordered symbol table methods.
***************************************************************************/
/**
* Returns the smallest key in this symbol table.
*
* @return the smallest key in this symbol table
* @throws NoSuchElementException if this symbol table is empty
*/
Key min() {
if (isEmpty()) throw runtime_error("called min() with empty symbol table");
return keys[0];
}
/**
* Returns the largest key in this symbol table.
*
* @return the largest key in this symbol table
* @throws NoSuchElementException if this symbol table is empty
*/
Key max() {
if (isEmpty()) throw runtime_error("called max() with empty symbol table");
return keys[n - 1];
}
/**
* Return the kth smallest key in this symbol table.
*
* @param k the order statistic
* @return the {@code k}th smallest key in this symbol table
* @throws IllegalArgumentException unless {@code k} is between 0 and
* <em>n</em>–1
*/
Key select(int k) {
if (k < 0 || k >= size()) {
throw runtime_error("called select() with invalid argument");
}
return keys[k];
}
/**
* Returns the largest key in this symbol table less than or equal to {@code key}.
*
* @param key the key
* @return the largest key in this symbol table less than or equal to {@code key}
* @throws NoSuchElementException if there is no such key
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
Key floor(Key key) {
int i = rank(key);
if (i < n && key == keys[i]) return keys[i];
if (i == 0) throw runtime_error("underflow");
else return keys[i - 1];
}
/**
* Returns the smallest key in this symbol table greater than or equal to {@code key}.
*
* @param key the key
* @return the smallest key in this symbol table greater than or equal to {@code key}
* @throws NoSuchElementException if there is no such key
* @throws IllegalArgumentException if {@code key} is {@code null}
*/
Key ceiling(Key key) {
int i = rank(key);
if (i == n) throw runtime_error("overflow");
else return keys[i];
}
/**
* Returns the number of keys in this symbol table in the specified range.
*
* @param lo minimum endpoint
* @param hi maximum endpoint
* @return the number of keys in this symbol table between {@code lo}
* (inclusive) and {@code hi} (inclusive)
* @throws IllegalArgumentException if either {@code lo} or {@code hi}
* is {@code null}
*/
int size(Key lo, Key hi) {
if (lo > hi) return 0;
if (contains(hi)) return rank(hi) - rank(lo) + 1;
else return rank(hi) - rank(lo);
}
typename vector<Key>::iterator begin() { return keys.begin(); }
typename vector<Key>::iterator end() { return keys.begin() + n; }
private:
// resize the underlying arrays
void resize(int capacity) {
keys.resize(capacity);
vals.resize(capacity);
}
private:
vector<Key> keys;
vector<Value> vals;
int n = 0;
static int INIT_CAPACITY;
};
template<typename Key, typename Value>
int BinarySearchST<Key, Value>::INIT_CAPACITY = 2;
#endif //CH3_BINARYSEARCHST_H