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
| #ifndef MY_HASH_TABLE #define MY_HASH_TABLE
#include "my_allocator.h" #include "my_iterator.h" #include "my_utility.h" #include "my_vector.h"
#include <vector> #include <functional> #include <cstddef> #include <initializer_list>
namespace mystl{
template <typename Key, typename Value> struct hash_node{ mystl::pair<Key, Value> data; hash_node* next{nullptr};
hash_node(const Key& k, const Value& v, hash_node* n = nullptr) : data(k, v), next(n) {} };
template < typename Key, typename Value, typename Hash = std::hash<Key>, typename KeyEqual = mystl::equal_to<Key>, typename Alloc = mystl::MyAllocator<hash_node<Key, Value>>> class MyHashTable{ public: using key_type = Key; using mapped_type = Value; using value_type = mystl::pair<Key,Value>; using size_type = std::size_t; using node_type = hash_node<Key, Value>; using allocator_type = Alloc;
private: mystl::MyVector<node_type*> buckets_; size_type size_{0}; float max_load_factor_{0.75f}; Hash hasher_; KeyEqual key_equal_; allocator_type alloc_;
public: MyHashTable(size_type bucket_count = 8) : buckets_(bucket_count, nullptr), size_(0) {} ~MyHashTable(){ clear(); }
bool empty() const noexcept {return size_ ==0;}
size_type size() const noexcept { return size_;} size_type bucket_count() const noexcept {return buckets_.size();}
void clear(){ for(auto& head : buckets_){ while(head){
} } }
void rehash(size_type new_count){ mystl::MyVector<node_type*> new_buckets(new_count, nullptr);
for(auto& head : buckets_){ while(head){ node_type* next = head->next; size_t index = hasher_(head->data.first) % new_count; head->next = new_buckets[index]; new_buckets[index] = head; head = next; } } buckets_.swap(new_buckets); }
float load_factor() const noexcept{ return static_cast<float>(size_) / static_cast<float>(buckets_.size()); }
void insert(const Key& key, const Value& value){ if(load_factor() > max_load_factor_){ rehash(buckets_.size() * 2); }
size_t idx = hasher_(key) % buckets_.size(); node_type* head = buckets_[idx];
for(node_type* node = head; node; node = node->next){ if(key_equal_(node->data.first, key)){ node->data.second = value; return; } }
node_type* new_node = alloc_.allocate(1); alloc_.construct(new_node, key, value, head); buckets_[idx] = new_node; ++size_; }
Value* find(const Key& key){ size_t idx = hasher_(key) % buckets_.size(); for(node_type* node = buckets_[idx]; node; node = node->next){ if(key_equal_(node->data.first, key)) return &node->data.second;; } return nullptr; }
bool erase(const Key& key){ size_t idx = hasher_(key) % buckets_.size(); node_type* prev = nullptr; node_type* curr = buckets_[idx]; while(curr){ if(key_equal_(curr->data.first, key)){ if(prev) prev->next = curr->next; else buckets_[idx] = curr->next;
alloc_.destroy(curr); alloc_.deallocate(curr, 1); --size_; return true; } prev = curr; curr = curr->next; } return false; }
Value& operator[](const Key& key){ Value* val = find(key); if(val) return *val; insert(key, Value()); return *find(key); }
void print_debug() const { for (size_t i = 0; i < buckets_.size(); ++i) { node_type* node = buckets_[i]; if (!node) continue; std::cout << "[" << i << "]: "; while (node) { std::cout << "(" << node->data.first << "," << node->data.second << ") -> "; node = node->next; } std::cout << "nullptr\n"; } } };
} #endif
|