123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- #ifndef HASHMAP_H
- #define HASHMAP_H
- #include <iostream>
- constexpr static int NUMBER_OF_PRIMES = 26;
- constexpr static int PRIMES[26] =
- {
- 17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911, 43853, 87719,
- 175447, 350899, 701819, 1403641, 2807303, 5614657, 11229331, 22458671,
- 44917381, 89834777, 179669557, 359339171, 718678369
- };
- template<class K, class V>
- class HashMap
- {
- public:
- HashMap(int initialLoad, unsigned int (*hasher)(K)) : hasher(hasher)
- {
- primeIndex = getHigherPrimeIndex(initialLoad);
- capacity = PRIMES[primeIndex];
- resizeCap = (capacity >> 2) * 3;
-
- data = new Node*[capacity];
- for(int i = 0; i < capacity; i++)
- {
- data[i] = nullptr;
- }
- entries = 0;
- }
-
- ~HashMap()
- {
- for(int i = 0; i < capacity; i++)
- {
- Node* n = data[i];
- while(n != nullptr)
- {
- Node* next = n->next;
- delete n;
- n = next;
- }
- }
- delete[] data;
- }
-
- int getCapacity() const
- {
- return capacity;
- }
-
- int getSize() const
- {
- return entries;
- }
-
- void put(K k, V v)
- {
- ensureCapacity();
- unsigned int hash = hasher(k) % capacity;
- if(data[hash] == nullptr)
- {
- data[hash] = new Node(k, v);
- entries++;
- }
- else
- {
- Node* n = data[hash];
- while(true)
- {
- if(n->k == k)
- {
- n->v = v;
- break;
- }
- else if(n->next == nullptr)
- {
- n->next = new Node(k, v);
- entries++;
- break;
- }
- n = n->next;
- }
- }
- }
-
- V remove(K k, V notFound)
- {
- unsigned int hash = hasher(k) % capacity;
- if(data[hash] == nullptr)
- {
- return notFound;
- }
- else
- {
- Node* n = data[hash];
- if(n->k == k)
- {
- V v = n->v;
- data[hash] = n->next;
- delete n;
- entries--;
- return v;
- }
-
- while(n->next != nullptr)
- {
- if(n->next->k == k)
- {
- Node* n = n->next;
- n->next = n->next->next;
- V v = n->v;
- delete n;
- entries--;
- return v;
- }
- }
- return notFound;
- }
- }
-
- bool remove(K k)
- {
- unsigned int hash = hasher(k) % capacity;
- if(data[hash] == nullptr)
- {
- return false;
- }
- else
- {
- Node* n = data[hash];
- if(n->k == k)
- {
- data[hash] = n->next;
- delete n;
- entries--;
- return true;
- }
-
- while(n->next != nullptr)
- {
- if(n->next->k == k)
- {
- Node* n = n->next;
- n->next = n->next->next;
- delete n;
- entries--;
- return true;
- }
- }
- return false;
- }
- }
-
- V get(K k, V error) const
- {
- unsigned int hash = hasher(k) % capacity;
- if(data[hash] == nullptr)
- {
- return error;
- }
- else
- {
- for(Node* n = data[hash]; n != nullptr; n = n->next)
- {
- if(n->k == k)
- {
- return n->v;
- }
- }
- return error;
- }
- }
-
- void clear()
- {
- for(int i = 0; i < capacity; i++)
- {
- Node* n = data[i];
- while(n != nullptr)
- {
- Node* next = n->next;
- delete n;
- n = next;
- }
- data[i] = nullptr;
- }
- entries = 0;
- }
-
- void print() const
- {
- for(int i = 0; i < capacity; i++)
- {
- Node* n = data[i];
- std::cout << i << ": ";
- if(n != nullptr)
- {
- std::cout << "(" << n->k << " = " << n->v << ")";
- while(n->next != nullptr)
- {
- n = n->next;
- std::cout << " -> (" << n->k << " = " << n->v << ")";
- }
- }
- std::cout << std::endl;
- }
- }
-
- void printStats() const
- {
- int fill = capacity;
- int cells = capacity;
- for(int i = 0; i < capacity; i++)
- {
- Node* n = data[i];
- if(n != nullptr)
- {
- while(n->next != nullptr)
- {
- fill++;
- n = n->next;
- }
- }
- }
- std::cout << (double) fill / cells << std::endl;
- }
-
- private:
- class Node
- {
- public:
- Node* next = nullptr;
- K k;
- V v;
-
- Node(K k, V v) : k(k), v(v)
- {
- }
- };
-
- int getHigherPrimeIndex(int lower) const
- {
- int low = 0;
- int high = NUMBER_OF_PRIMES - 1;
- int mid;
- while(true)
- {
- if(low == high)
- {
- return low;
- }
- mid = (high + low) >> 1;
- if(PRIMES[mid] >= lower)
- {
- high = mid;
- }
- else
- {
- low = mid + 1;
- }
- }
- }
-
- void ensureCapacity()
- {
- if(entries < resizeCap)
- {
- return;
- }
-
- primeIndex++;
- if(primeIndex >= NUMBER_OF_PRIMES)
- {
- return;
- }
-
- int oldCapacity = capacity;
- capacity = PRIMES[primeIndex];
-
- //std::cout << "resize from " << oldCapacity << " to " << capacity << std::endl;
-
- resizeCap = (capacity >> 2) * 3;
-
- Node** newData = new Node*[capacity];
- for(int i = 0; i < capacity; i++)
- {
- newData[i] = nullptr;
- }
-
- for(int i = 0; i < oldCapacity; i++)
- {
- Node* old = data[i];
- if(old != nullptr)
- {
- unsigned int hash = hasher(old->k) % capacity;
- Node* n = newData[hash];
- if(n == nullptr)
- {
- newData[hash] = old;
- }
- else
- {
- while(n->next != nullptr)
- {
- n = n->next;
- }
- n->next = old;
- }
-
- while(old->next != nullptr)
- {
- n = old->next;
- old->next = nullptr;
- hash = hasher(n->k) % capacity;
- Node* m = newData[hash];
- if(m == nullptr)
- {
- newData[hash] = n;
- }
- else
- {
- while(m->next != nullptr)
- {
- m = m->next;
- }
- m->next = n;
- }
- old = n;
- }
- }
- }
-
- delete[] data;
- data = newData;
- }
-
- unsigned int (*hasher)(K);
-
- int primeIndex;
- int capacity;
- int resizeCap;
-
- Node** data;
- int entries;
- };
- #endif
|