1.定義
unordered_map
?是 C++ 標準庫中的哈希表容器,特點是無序存儲、平均 O (1) 時間復雜度的插入 / 查找 / 刪除操作。其核心原理是通過哈希函數將關鍵字映射到哈希桶(bucket),再通過鏈表或紅黑樹處理哈希沖突。
2.實現原理
1. 哈希表(Hash Table)
- 作用:存儲鍵值對的底層數據結構,由哈希桶數組組成。
- 結構:
vector<Node*>
?或?vector<list<Node>>
,每個元素(桶)對應一個鏈表(處理哈希沖突)。
2. 哈希函數(Hash Function)
- 作用:將關鍵字(Key)映射為哈希桶的索引(整數)。
- 要求:
- 輸出范圍需在哈希桶數組大小范圍內(通過取模?
% bucket_count
?實現)。 - 盡可能減少哈希沖突(不同 Key 映射到同一索引)。
- 輸出范圍需在哈希桶數組大小范圍內(通過取模?
?例子:
template <typename Key>
size_t HashFunc(const Key& key) {// 對整數直接取哈希return static_cast<size_t>(key);
}// 對字符串的哈希
template <>
size_t HashFunc(const std::string& key) {size_t hash = 0;for (char c : key) {hash = hash * 31 + c; // 31 是質數,減少沖突}return hash;
}
3. 哈希沖突(Hash Collision)
- 問題:不同的 Key 通過哈希函數得到相同的桶索引。
- 解決方式:
- 鏈地址法(最常用):每個桶對應一個鏈表,沖突的鍵值對依次插入鏈表。
- 開放定址法:沖突時尋找下一個空桶(較少用于?
unordered_map
)。
4. 負載因子(Load Factor)
- 定義:
負載因子 = 元素個數 / 桶數量
。 - 作用:衡量哈希表的擁擠程度,超過閾值(通常為 1.0)時需要擴容。
- 擴容機制:
- 創建新的、更大的桶數組(通常為原大小的 2 倍,且為質數)。
- 將所有元素重新哈希(rehash)到新桶中,避免哈希沖突加劇。
5. 鍵值對(Key-Value Pair)
- 結構:存儲關鍵字(Key)和值(Value)的節點,例如:
template <typename Key, typename Value>
struct Node {Key key;Value value;Node* next; // 指向鏈表中下一個節點(處理沖突)Node(const Key& k, const Value& v) : key(k), value(v), next(nullptr) {}
};
3.主要實現
1. 構造函數與析構函數
template <typename Key, typename Value>
class my_UnorderedMap {
private:std::vector<Node<Key, Value>*> buckets; // 哈希桶數組size_t size; // 當前元素個數size_t bucket_count; // 桶數量const float load_factor_threshold = 1.0f; // 負載因子閾值public:// 構造函數:初始化桶數量(默認 10 個桶)my_UnorderedMap(size_t init_buckets = 10) : bucket_count(init_buckets), size(0) {buckets.resize(bucket_count, nullptr);}// 析構函數:釋放所有節點和桶~my_UnorderedMap() {for (auto bucket : buckets) {Node<Key, Value>* cur = bucket;while (cur) {Node<Key, Value>* next = cur->next;delete cur;cur = next;}}}
};
2.插入操作
bool my_insert(const Key& key, const Value& value) {// 檢查是否需要擴容if (size * 1.0 / bucket_count >= load_factor_threshold) {rehash(bucket_count * 2); // 擴容為原大小的 2 倍}// 計算哈希索引size_t index = HashFunc(key) % bucket_count;// 檢查 Key 是否已存在(不允許重復 Key)Node<Key, Value>* cur = buckets[index];while (cur) {if (cur->key == key) {return false; // Key 已存在,插入失敗}cur = cur->next;}// 插入新節點(頭插法)Node<Key, Value>* new_node = new Node<Key, Value>(key, value);new_node->next = buckets[index]; // 新節點指向原鏈表頭buckets[index] = new_node; // 桶頭指向新節點size++;return true;
}
?3.查找
Value* my_find(const Key& key) {size_t index = HashFunc(key) % bucket_count;Node<Key, Value>* cur = buckets[index];while (cur) {if (cur->key == key) {return &(cur->value); // 找到 Key,返回值的指針}cur = cur->next;}return nullptr; // 未找到
}
?4.刪除
bool my_erase(const Key& key) {size_t index = HashFunc(key) % bucket_count;Node<Key, Value>* cur = buckets[index];Node<Key, Value>* prev = nullptr;while (cur) {if (cur->key == key) {// 移除節點if (prev == nullptr) {// 頭節點刪除buckets[index] = cur->next;} else {prev->next = cur->next;}delete cur;size--;return true;}prev = cur;cur = cur->next;}return false; // 未找到 Key
}
?5.擴容
void my_rehash(size_t new_bucket_count) {if (new_bucket_count <= bucket_count) return; // 新桶數量必須更大// 創建新桶數組std::vector<Node<Key, Value>*> new_buckets(new_bucket_count, nullptr);// 將舊桶中的元素重新哈希到新桶for (size_t i = 0; i < bucket_count; i++) {Node<Key, Value>* cur = buckets[i];while (cur) {Node<Key, Value>* next = cur->next; // 保存下一個節點// 計算新索引size_t new_index = HashFunc(cur->key) % new_bucket_count;// 插入新桶(頭插法)cur->next = new_buckets[new_index];new_buckets[new_index] = cur;cur = next;}}// 替換舊桶數組buckets.swap(new_buckets);bucket_count = new_bucket_count;
}
6.移動復制和拷貝賦值
// 拷貝賦值運算符my_UnorderedMap& operator=(const UnorderedMap& other) {if (this != &other) {clear();bucket_count = other.bucket_count;load_factor_threshold = other.load_factor_threshold;hash_fn = other.hash_fn;equal_fn = other.equal_fn;buckets.resize(bucket_count, nullptr);for (size_t i = 0; i < other.bucket_count; ++i) {Node* current = other.buckets[i];while (current != nullptr) {insert(current->key, current->value);current = current->next;}}}return *this;}// 移動賦值運算符my_UnorderedMap& operator=(UnorderedMap&& other) noexcept {if (this != &other) {clear();buckets = std::move(other.buckets);element_count = other.element_count;bucket_count = other.bucket_count;load_factor_threshold = other.load_factor_threshold;hash_fn = std::move(other.hash_fn);equal_fn = std::move(other.equal_fn);other.element_count = 0;other.bucket_count = 0;}return *this;}
---完整代碼;
#include <vector>
#include <cstddef>
#include <functional>
#include <stdexcept>template <typename Key, typename Value, typename Hash = std::hash<Key>, typename Equal = std::equal_to<Key>>
class my_UnorderedMap {
private:// 鍵值對節點結構struct Node {Key key;Value value;Node* next;Node(const Key& k, const Value& v) : key(k), value(v), next(nullptr) {}};std::vector<Node*> buckets; // 哈希桶數組size_t element_count; // 當前元素數量size_t bucket_count; // 桶的數量float load_factor_threshold; // 負載因子閾值// 哈希函數包裝器Hash hash_fn;// 相等比較器Equal equal_fn;// 檢查是否為質數bool is_prime(size_t num) const {if (num <= 1) return false;if (num == 2) return true;if (num % 2 == 0) return false;for (size_t i = 3; i * i <= num; i += 2) {if (num % i == 0) return false;}return true;}// 獲取下一個質數size_t next_prime(size_t num) const {if (num <= 2) return 2;size_t candidate = num;if (candidate % 2 == 0) ++candidate;while (!is_prime(candidate)) {candidate += 2;}return candidate;}// 重新哈希所有元素到新的桶數組void my_rehash(size_t new_bucket_count) {if (new_bucket_count <= bucket_count) return;std::vector<Node*> new_buckets(new_bucket_count, nullptr);// 將舊桶中的所有節點遷移到新桶for (size_t i = 0; i < bucket_count; ++i) {Node* current = buckets[i];while (current != nullptr) {Node* next = current->next;size_t new_index = hash_fn(current->key) % new_bucket_count;current->next = new_buckets[new_index];new_buckets[new_index] = current;current = next;}}// 交換新舊桶數組buckets.swap(new_buckets);bucket_count = new_bucket_count;}public:// 構造函數explicit my_UnorderedMap(size_t initial_buckets = 10, const Hash& hash = Hash(), const Equal& equal = Equal()): element_count(0), bucket_count(next_prime(initial_buckets)),load_factor_threshold(1.0f),hash_fn(hash),equal_fn(equal) {buckets.resize(bucket_count, nullptr);}// 析構函數~my_UnorderedMap() {clear();}// 拷貝構造函數my_UnorderedMap(const UnorderedMap& other): element_count(0), bucket_count(other.bucket_count),load_factor_threshold(other.load_factor_threshold),hash_fn(other.hash_fn),equal_fn(other.equal_fn) {buckets.resize(bucket_count, nullptr);for (size_t i = 0; i < other.bucket_count; ++i) {Node* current = other.buckets[i];while (current != nullptr) {insert(current->key, current->value);current = current->next;}}}// 移動構造函數my_UnorderedMap(UnorderedMap&& other) noexcept: buckets(std::move(other.buckets)),element_count(other.element_count),bucket_count(other.bucket_count),load_factor_threshold(other.load_factor_threshold),hash_fn(std::move(other.hash_fn)),equal_fn(std::move(other.equal_fn)) {other.element_count = 0;other.bucket_count = 0;}// 拷貝賦值運算符my_UnorderedMap& operator=(const UnorderedMap& other) {if (this != &other) {clear();bucket_count = other.bucket_count;load_factor_threshold = other.load_factor_threshold;hash_fn = other.hash_fn;equal_fn = other.equal_fn;buckets.resize(bucket_count, nullptr);for (size_t i = 0; i < other.bucket_count; ++i) {Node* current = other.buckets[i];while (current != nullptr) {insert(current->key, current->value);current = current->next;}}}return *this;}// 移動賦值運算符my_UnorderedMap& operator=(UnorderedMap&& other) noexcept {if (this != &other) {clear();buckets = std::move(other.buckets);element_count = other.element_count;bucket_count = other.bucket_count;load_factor_threshold = other.load_factor_threshold;hash_fn = std::move(other.hash_fn);equal_fn = std::move(other.equal_fn);other.element_count = 0;other.bucket_count = 0;}return *this;}// 插入元素bool my_insert(const Key& key, const Value& value) {// 檢查負載因子,必要時擴容if (static_cast<float>(element_count) / bucket_count >= load_factor_threshold) {rehash(next_prime(bucket_count * 2));}size_t index = hash_fn(key) % bucket_count;Node* current = buckets[index];// 檢查鍵是否已存在while (current != nullptr) {if (equal_fn(current->key, key)) {return false; // 鍵已存在,插入失敗}current = current->next;}// 創建新節點并插入鏈表頭部Node* new_node = new Node(key, value);new_node->next = buckets[index];buckets[index] = new_node;++element_count;return true;}// 查找元素Value* my_find(const Key& key) {size_t index = hash_fn(key) % bucket_count;Node* current = buckets[index];while (current != nullptr) {if (equal_fn(current->key, key)) {return &(current->value);}current = current->next;}return nullptr; // 未找到}// 查找元素(const 版本)const Value* my_find(const Key& key) const {size_t index = hash_fn(key) % bucket_count;Node* current = buckets[index];while (current != nullptr) {if (equal_fn(current->key, key)) {return &(current->value);}current = current->next;}return nullptr; // 未找到}// 重載[]運算符Value& operator[](const Key& key) {Value* value_ptr = find(key);if (value_ptr == nullptr) {// 鍵不存在,插入默認值insert(key, Value());value_ptr = find(key);}return *value_ptr;}// 刪除元素bool my_erase(const Key& key) {size_t index = hash_fn(key) % bucket_count;Node* current = buckets[index];Node* previous = nullptr;while (current != nullptr) {if (equal_fn(current->key, key)) {if (previous == nullptr) {// 刪除頭節點buckets[index] = current->next;} else {previous->next = current->next;}delete current;--element_count;return true;}previous = current;current = current->next;}return false; // 未找到鍵}// 獲取元素數量size_t size() const {return element_count;}// 檢查是否為空bool my_empty() const {return element_count == 0;}// 清空容器void clear() {for (size_t i = 0; i < bucket_count; ++i) {Node* current = buckets[i];while (current != nullptr) {Node* next = current->next;delete current;current = next;}buckets[i] = nullptr;}element_count = 0;}// 獲取負載因子float load_factor() const {return static_cast<float>(element_count) / bucket_count;}// 獲取負載因子閾值float max_load_factor() const {return load_factor_threshold;}// 設置負載因子閾值void max_load_factor(float new_threshold) {if (new_threshold > 0) {load_factor_threshold = new_threshold;}}// 調整桶的數量void reserve(size_t count) {size_t new_bucket_count = next_prime(count);if (new_bucket_count > bucket_count) {rehash(new_bucket_count);}}// 迭代器類class Iterator {private:Node* current;const std::vector<Node*>* buckets;size_t bucket_index;size_t bucket_count;// 移動到下一個非空桶void move_to_next_bucket() {while (current == nullptr && bucket_index < bucket_count) {++bucket_index;if (bucket_index < bucket_count) {current = (*buckets)[bucket_index];}}}public:Iterator(Node* node, const std::vector<Node*>* b, size_t index, size_t count): current(node), buckets(b), bucket_index(index), bucket_count(count) {if (current == nullptr) {move_to_next_bucket();}}Iterator& operator++() {if (current != nullptr) {current = current->next;if (current == nullptr) {++bucket_index;move_to_next_bucket();}}return *this;}bool operator==(const Iterator& other) const {return current == other.current;}bool operator!=(const Iterator& other) const {return !(*this == other);}std::pair<const Key&, Value&> operator*() const {return {current->key, current->value};}std::pair<const Key&, Value&>* operator->() const {// 這里簡化實現,實際需要返回一個代理對象throw std::runtime_error("Arrow operator not fully implemented");}};// 迭代器接口Iterator begin() const {if (empty()) {return end();}return Iterator(buckets[0], &buckets, 0, bucket_count);}Iterator end() const {return Iterator(nullptr, &buckets, bucket_count, bucket_count);}
};