-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathht.h
450 lines (386 loc) · 13.7 KB
/
ht.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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
#ifndef HT_H
#define HT_H
#include <vector>
#include <iostream>
#include <cmath>
typedef size_t HASH_INDEX_T;
// Complete - Base Prober class
template <typename KeyType>
struct Prober {
// Data members
HASH_INDEX_T start_; // initial hash location, h(k)
HASH_INDEX_T m_; // table size
size_t numProbes_; // probe attempts for statistic tracking
static const HASH_INDEX_T npos = (HASH_INDEX_T)-1; // used to indicate probing failed
void init(HASH_INDEX_T start, HASH_INDEX_T m, const KeyType& key)
{
(void) key; // avoid unused argument warnings since base class doesn't use key
start_ = start;
m_ = m;
numProbes_ = 0;
}
HASH_INDEX_T next() {
throw std::logic_error("Not implemented...should use derived class");
}
};
// Almost Complete - Fill in the if statement below.
template <typename KeyType>
struct LinearProber : public Prober<KeyType> {
HASH_INDEX_T next()
{
// Complete the condition below that indicates failure
// to find the key or an empty slot
if( /* Fill me in */ ) {
return this->npos;
}
HASH_INDEX_T loc = (this->start_ + this->numProbes_) % this->m_;
this->numProbes_++;
return loc;
}
};
// To be completed
template <typename KeyType, typename Hash2>
struct DoubleHashProber : public Prober<KeyType>
{
Hash2 h2_; /// h2(k)
HASH_INDEX_T dhstep_; /// Stepsize to use for double hash probing
/// Moduli to use for double hashing as table increases (resizes)
static const HASH_INDEX_T DOUBLE_HASH_MOD_VALUES[];
/// The number of elements in the array above
static const int DOUBLE_HASH_MOD_SIZE;
//==================================
// Add data members, as desired
//==================================
private:
// Complete
HASH_INDEX_T findModulusToUseFromTableSize(HASH_INDEX_T currTableSize)
{
HASH_INDEX_T modulus = DOUBLE_HASH_MOD_VALUES[0];
// find the modulus that is just smaller than the table size
for(int i=0; i < DOUBLE_HASH_MOD_SIZE && DOUBLE_HASH_MOD_VALUES[i] < currTableSize; i++)
{
modulus = DOUBLE_HASH_MOD_VALUES[i];
}
return modulus;
}
public:
/**
* @brief Construct a new Double Hash Prober
* Accepts information that must be provided outside the hash table
* (i.e. apart from internal hash table info/parameters)
*
*
* @param h2 h2(k) - Object with an operator()(const KeyType&) defined for it
*/
DoubleHashProber(const Hash2& h2 = Hash2()) : h2_(h2) {}
/**
* @brief Supplies info the hash table must provide
*
* @param start Starting location for probing (i.e. h1(k))
* @param m Table size
* @param key Key (in case further hashing is necessary)
*/
// Complete
void init(HASH_INDEX_T start, HASH_INDEX_T m, const KeyType& key)
{
Prober<KeyType>::init(start, m, key);
HASH_INDEX_T modulus = findModulusToUseFromTableSize(m);
// Compute probe stepsize given modulus and h2(k)
dhstep_ = modulus - h2_(key) % modulus;
}
// To be completed
HASH_INDEX_T next()
{
}
};
// Initialization of static array (do not alter)
template <typename KeyType, typename Hash2>
const HASH_INDEX_T DoubleHashProber<KeyType, Hash2>::DOUBLE_HASH_MOD_VALUES[] =
{
7, 19, 43, 89, 193, 389, 787, 1583, 3191, 6397, 12841, 25703, 51431, 102871,
205721, 411503, 823051, 1646221, 3292463, 6584957, 13169963, 26339921, 52679927,
105359939, 210719881, 421439749, 842879563, 1685759113
};
// Initialization of static array size (do not alter)
template <typename KeyType, typename Hash2>
const int DoubleHashProber<KeyType, Hash2>::DOUBLE_HASH_MOD_SIZE =
sizeof(DoubleHashProber<KeyType, Hash2>::DOUBLE_HASH_MOD_VALUES)/sizeof(HASH_INDEX_T);
// Hash Table Interface
template<
typename K,
typename V,
typename Prober = LinearProber<K>,
typename Hash = std::hash<K>,
typename KEqual = std::equal_to<K> >
class HashTable
{
public:
typedef K KeyType;
typedef V ValueType;
typedef std::pair<KeyType, ValueType> ItemType;
typedef Hash Hasher;
struct HashItem {
ItemType item;
bool deleted;
HashItem(const ItemType& newItem){
item = newItem;
deleted = false;
}
};
/**
* @brief Construct a new Hash Table object
*
* @param resizeAlpha Loading factor threshold at which the table should resize
* @param prober Probing object of type Prober
* @param hash Hash functor that supports hash(key) and returns a HASH_INDEX_T
* @param kequal Functor that checks equality of two KeyType objects
*/
HashTable(
double resizeAlpha = 0.4,
const Prober& prober = Prober(),
const Hasher& hash = Hasher(),
const KEqual& kequal = KEqual());
/**
* @brief Destroy the Hash Table object and delete all remaining
* key,value pairs
*
*/
~HashTable();
/**
* @brief Returns true if the table has no non-deleted key,value pairs,
* and false otherwise
*
*/
bool empty() const;
/**
* @brief Returns number of (non-deleted) key,value pairs in the table
*
* @return size_t
*/
size_t size() const;
/**
* @brief Inserts a new item into the map, or, if an item with the
* given key already exists, it updates the Value of that item
* with the second value of the pair, p
*
* @param p Pair to insert
* @throw std::logic_error If no free location can be found
*/
void insert(const ItemType& p);
/**
* @brief Removes (marks as deleted) the item with the given key.
* Does nothing if an item with the given key does not exist.
*
* @param key
*/
void remove(const KeyType& key);
/**
* @brief Finds an item with the given key and returns a pointer
* to the key,value pair
*
* @param key
* @return ItemType const* nullptr is returned if the key does not exist
*/
ItemType const * find(const KeyType& key) const;
ItemType * find(const KeyType& key);
/**
* @brief Returns the value corresponding to the given key
*
* @param key
* throw std::out_of_range if the key does not exist
* @return ValueType Value associated with key
*/
const ValueType& at(const KeyType& key) const;
ValueType& at(const KeyType& key);
const ValueType& operator[](const KeyType& key) const;
ValueType& operator[](const KeyType& key);
// Debug / Performance functions
void reportAll(std::ostream& out) const;
void clearTotalProbes() { totalProbes_ = 0; }
size_t totalProbes() const { return totalProbes_; }
private:
/**
* @brief Helper routine to find a given key
*
* @param key
* @return HashItem* returns nullptr if key does not exist
*/
HashItem * internalFind(const KeyType& key) const;
/**
* @brief Performs the probing sequence and returns the index
* of the table location with the given key or the location where
* key can be inserted (i.e. the index now contains nullptr) but is
* available.
*
* @param key
* @return returns npos is the key does not exist and
* no free location is available
*/
HASH_INDEX_T probe(const KeyType& key) const;
// Constant to signify an invalid hash location is being returned
static const HASH_INDEX_T npos = Prober::npos;
/**
* @brief Resizes the hash table replacing the old with a new
* table of the next prime size given in CAPACITIES. Must rehash
* all non-deleted items while freeing all deleted items.
*
* Must run in O(m) where m is the new table size
*
* @throws std::logic_error if no more CAPACITIES exist
*/
void resize();
// Data members
std::vector<HashItem*> table_; // actual hash table
Hasher hash_;
KEqual kequal_;
mutable Prober prober_; // mutable allows const member functions to modify this member
// debug/performance counters
mutable size_t totalProbes_; // mutable allows const member functions to modify this member
// prime capacities to be used when resizing/rehashing is needed
static const HASH_INDEX_T CAPACITIES[];
HASH_INDEX_T mIndex_; // index to CAPACITIES
// ADD MORE DATA MEMBERS HERE, AS NECESSARY
};
// ----------------------------------------------------------------------------
// Hash Table Implementation
// ----------------------------------------------------------------------------
// Static array of prime table sizes
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
const HASH_INDEX_T HashTable<K,V,Prober,Hash,KEqual>::CAPACITIES[] =
{
11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853, 25717, 51437, 102877,
205759, 411527, 823117, 1646237, 3292489, 6584983, 13169977, 26339969, 52679969,
105359969, 210719881, 421439783, 842879579, 1685759167
};
// To be completed
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
HashTable<K,V,Prober,Hash,KEqual>::HashTable(
double resizeAlpha, const Prober& prober, const Hasher& hash, const KEqual& kequal)
: hash_(hash), kequal_(kequal), prober_(prober)
{
// Initialize any other data members as necessary
}
// To be completed
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
HashTable<K,V,Prober,Hash,KEqual>::~HashTable()
{
}
// To be completed
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
bool HashTable<K,V,Prober,Hash,KEqual>::empty() const
{
}
// To be completed
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
size_t HashTable<K,V,Prober,Hash,KEqual>::size() const
{
}
// To be completed
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
void HashTable<K,V,Prober,Hash,KEqual>::insert(const ItemType& p)
{
}
// To be completed
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
void HashTable<K,V,Prober,Hash,KEqual>::remove(const KeyType& key)
{
}
// Complete
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
typename HashTable<K,V,Prober,Hash,KEqual>::ItemType const * HashTable<K,V,Prober,Hash,KEqual>::find(const KeyType& key) const
{
HASH_INDEX_T h = this->probe(key);
if((npos == h) || nullptr == table_[h] ){
return nullptr;
}
return &table_[h]->item;
}
// Complete
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
typename HashTable<K,V,Prober,Hash,KEqual>::ItemType * HashTable<K,V,Prober,Hash,KEqual>::find(const KeyType& key)
{
HASH_INDEX_T h = this->probe(key);
if((npos == h) || nullptr == table_[h] ){
return nullptr;
}
return &table_[h]->item;
}
// Complete
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
const typename HashTable<K,V,Prober,Hash,KEqual>::ValueType& HashTable<K,V,Prober,Hash,KEqual>::at(const KeyType& key) const
{
HashItem const * item = this->internalFind(key);
if(item == nullptr) { throw std::out_of_range("Bad key"); }
return item->item.second;
}
// Complete
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
typename HashTable<K,V,Prober,Hash,KEqual>::ValueType& HashTable<K,V,Prober,Hash,KEqual>::at(const KeyType& key)
{
HashItem * item = this->internalFind(key);
if(item == nullptr) { throw std::out_of_range("Bad key"); }
return item->item.second;
}
// Complete
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
const typename HashTable<K,V,Prober,Hash,KEqual>::ValueType& HashTable<K,V,Prober,Hash,KEqual>::operator[](const KeyType& key) const
{
return this->at(key);
}
// Complete
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
typename HashTable<K,V,Prober,Hash,KEqual>::ValueType& HashTable<K,V,Prober,Hash,KEqual>::operator[](const KeyType& key)
{
return this->at(key);
}
// Complete
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
typename HashTable<K,V,Prober,Hash,KEqual>::HashItem* HashTable<K,V,Prober,Hash,KEqual>::internalFind(const KeyType& key) const
{
HASH_INDEX_T h = this->probe(key);
if((npos == h) || nullptr == table_[h] ){
return nullptr;
}
return table_[h];
}
// To be completed
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
void HashTable<K,V,Prober,Hash,KEqual>::resize()
{
}
// Almost complete
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
HASH_INDEX_T HashTable<K,V,Prober,Hash,KEqual>::probe(const KeyType& key) const
{
HASH_INDEX_T h = hash_(key) % CAPACITIES[mIndex_];
prober_.init(h, CAPACITIES[mIndex_], key);
HASH_INDEX_T loc = prober_.next();
totalProbes_++;
while(Prober::npos != loc)
{
if(nullptr == table_[loc] ) {
return loc;
}
// fill in the condition for this else if statement which should
// return 'loc' if the given key exists at this location
else if(/* Fill me in */) {
return loc;
}
loc = prober_.next();
totalProbes_++;
}
return npos;
}
// Complete
template<typename K, typename V, typename Prober, typename Hash, typename KEqual>
void HashTable<K, V, Prober, Hash, KEqual>::reportAll(std::ostream& out) const
{
for(HASH_INDEX_T i = 0; i < CAPACITIES[mIndex_]; ++i)
{
if(table_[i] != nullptr)
{
out << "Bucket " << i << ": " << table_[i]->item.first << " " << table_[i]->item.second << std::endl;
}
}
}
#endif