✨️ 复制成功,转载请标注本文地址

无序map封装

5334 字
27 分钟
无序map封装

unordermap用法#

unordered_map 是 C++ 标准库中的关联容器,提供了基于哈希表的键值对存储结构。与 map (基于红黑树实现)不同,unordered_map 提供的是平均常数时间复杂度的查找、插入和删除操作,但不保证元素的顺序。

以下是 unordered_map 的详细用法说明:

1. 头文件#

要使用 unordered_map,需要包含头文件:

#include <unordered_map>

2. 基本定义#

unordered_map 的基本模板定义如下:

std::unordered_map<KeyType, ValueType, Hash = std::hash<KeyType>, KeyEqual = std::equal_to<KeyType>, Allocator = std::allocator<std::pair<const KeyType, ValueType>>>

常用模板参数:#

  • KeyType:键的类型,需要支持哈希运算和相等比较。
  • ValueType:值的类型。
  • Hash:哈希函数,默认为 std::hash<KeyType>
  • KeyEqual:键相等的比较函数,默认为 std::equal_to<KeyType>
  • Allocator:内存分配器,默认为 std::allocator

3. 常用操作#

3.1 创建和初始化#

#include <iostream>
#include <unordered_map>
#include <string>
int main() {
// 创建一个空的 unordered_map,键为 string,值为 int
std::unordered_map<std::string, int> umap;
// 使用初始化列表初始化
std::unordered_map<std::string, int> umap_init = {
{"apple", 3},
{"banana", 5},
{"orange", 2}
};
// 使用其他容器范围初始化
std::map<std::string, int> ordered_map = {{"carrot", 4}, {"lettuce", 1}};
std::unordered_map<std::string, int> umap_from_map(ordered_map.begin(), ordered_map.end());
return 0;
}

3.2 插入元素#

// 方法1:使用下标操作符
umap["grape"] = 7;
// 方法2:使用 insert
umap.insert({"melon", 6});
// 方法3:使用 emplace,直接在容器内部构造元素
umap.emplace("kiwi", 4);

3.3 访问元素#

// 使用下标操作符访问或插入
int apple_count = umap["apple"]; // 如果 "apple" 不存在,会插入一个默认值
// 使用 at() 方法访问,不存在时会抛出异常
try {
int banana_count = umap.at("banana");
} catch (const std::out_of_range& e) {
std::cerr << "Key not found." << std::endl;
}
// 使用 find() 方法查找
auto it = umap.find("orange");
if (it != umap.end()) {
std::cout << "Orange count: " << it->second << std::endl;
} else {
std::cout << "Orange not found." << std::endl;
}

3.4 删除元素#

// 根据键删除
umap.erase("grape");
// 根据迭代器删除
auto it = umap.find("banana");
if (it != umap.end()) {
umap.erase(it);
}
// 清空整个容器
umap.clear();

3.5 遍历元素#

for (const auto& pair : umap) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
// 使用迭代器
for (auto it = umap.begin(); it != umap.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}

3.6 其他常用方法#

// 获取大小
size_t size = umap.size();
// 检查是否为空
bool is_empty = umap.empty();
// 获取桶的数量(用于哈希表内部结构)
size_t bucket_count = umap.bucket_count();
// 重新哈希,调整桶的数量
umap.rehash(20);
// 从一个容器中移交元素到另一个容器
std::unordered_map<std::string, int> umap2 = std::move(umap);

4. 性能优化#

4.1 预分配桶数#

如果预先知道元素的大致数量,可以通过 reserve 预分配内存,以减少哈希表的重哈希开销:

umap.reserve(100); // 预分配足够容纳100个元素的桶

4.2 自定义哈希函数#

如果键的类型是自定义类型或需要特殊的哈希策略,可以自定义哈希函数。例如,自定义结构体作为键:

struct Point {
int x;
int y;
bool operator==(const Point& other) const {
return x == other.x && y == other.y;
}
};
// 自定义哈希函数
struct PointHash {
std::size_t operator()(const Point& p) const {
return std::hash<int>()(p.x) ^ (std::hash<int>()(p.y) << 1);
}
};
// 定义 unordered_map 使用自定义哈希函数
std::unordered_map<Point, std::string, PointHash> point_map;
point_map[{1, 2}] = "A";
point_map[{3, 4}] = "B";

4.3 自定义键相等比较#

如果需要自定义键的比较逻辑,可以提供自定义的 KeyEqual 函数对象:

struct PointEqual {
bool operator()(const Point& a, const Point& b) const {
return (a.x == b.x) && (a.y == b.y);
}
};
// 定义 unordered_map 使用自定义哈希和比较函数
std::unordered_map<Point, std::string, PointHash, PointEqual> point_map;

5. 与 map 的比较#

  • 底层实现unordered_map 基于哈希表,实现的操作平均时间复杂度为常数级别;map 基于红黑树,实现的查找、插入、删除操作时间复杂度为对数级别。
  • 元素顺序unordered_map 不保证元素的顺序;map 按键的顺序(通常是升序)存储元素。
  • 适用场景:当需要快速查找、插入和删除,且不关心元素顺序时,选择 unordered_map;当需要有序存储或按顺序遍历时,选择 map

6. 完整示例#

以下是一个使用 unordered_map 的完整示例:

#include <iostream>
#include <unordered_map>
#include <string>
// 自定义类型
struct Person {
std::string name;
int age;
bool operator==(const Person& other) const {
return name == other.name && age == other.age;
}
};
// 自定义哈希函数
struct PersonHash {
std::size_t operator()(const Person& p) const {
return std::hash<std::string>()(p.name) ^ (std::hash<int>()(p.age) << 1);
}
};
int main() {
// 创建一个 unordered_map,键为 string,值为 int
std::unordered_map<std::string, int> fruit_count;
fruit_count["apple"] = 5;
fruit_count["banana"] = 3;
fruit_count.emplace("orange", 2);
// 访问元素
std::cout << "Apple count: " << fruit_count["apple"] << std::endl;
// 遍历
for (const auto& pair : fruit_count) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
// 使用自定义类型作为键
std::unordered_map<Person, std::string, PersonHash> person_map;
Person p1{"Alice", 30};
Person p2{"Bob", 25};
person_map[p1] = "Engineer";
person_map.emplace(p2, "Designer");
// 访问自定义类型键的值
Person p3{"Alice", 30};
std::cout << "Alice's job: " << person_map[p3] << std::endl;
return 0;
}

输出示例

Apple count: 5
banana: 3
orange: 2
apple: 5
Alice's job: Engineer

手写unordermap#

1. 哈希表的基本原理#

哈希表是一种基于键值对的数据结构,通过哈希函数(Hash Function)将键映射到表中的一个索引位置,以实现快速的数据访问。哈希表的关键特性包括:

  • 哈希函数:将键映射到表中一个特定的桶(Bucket)或槽(Slot)。
  • 冲突解决:当不同的键通过哈希函数映射到同一个桶时,需要一种机制来处理这些冲突。常见的方法有链地址法(Separate Chaining)和开放地址法(Open Addressing)。
  • 负载因子(Load Factor):表示表中已存储元素的数量与表大小之间的比率。高负载因子可能导致更多的冲突,需要通过扩容来维持性能。

在本实现中,我们将采用链地址法来处理哈希冲突,即每个桶存储一个链表(或其他动态数据结构)来存储具有相同哈希值的元素。

2. 数据结构设计#

HashNode 结构#

HashNode 用于存储键值对及相关的指针,以构建链表。每个 HashNode 包含键、值和指向下一个节点的指针。

#include <vector>
#include <list>
#include <utility> // For std::pair
#include <functional> // For std::hash
#include <iterator> // For iterator_traits
#include <stdexcept> // For exceptions
// HashNode 结构定义
template <typename Key, typename T>
struct HashNode {
std::pair<const Key, T> data;
HashNode* next;
HashNode(const Key& key, const T& value)
: data(std::make_pair(key, value)), next(nullptr) {}
};

MyHashMap 类定义#

MyHashMap 是我们自定义的哈希表实现,支持基本的 Map 操作和迭代器功能。它使用一个向量(std::vector)来存储桶,每个桶是一个链表,用于处理冲突。

template <typename Key, typename T, typename Hash = std::hash<Key>>
class MyHashMap {
public:
// 迭代器类前向声明
class Iterator;
// 类型定义
using key_type = Key;
using mapped_type = T;
using value_type = std::pair<const Key, T>;
using size_type = size_t;
// 构造函数及析构函数
MyHashMap(size_type initial_capacity = 16, double max_load_factor = 0.75);
~MyHashMap();
// 禁止拷贝构造和赋值
MyHashMap(const MyHashMap&) = delete;
MyHashMap& operator=(const MyHashMap&) = delete;
// 基本操作
void insert(const Key& key, const T& value);
T* find(const Key& key);
const T* find(const Key& key) const;
bool erase(const Key& key);
size_type size() const;
bool empty() const;
void clear();
// 迭代器操作
Iterator begin();
Iterator end();
// 迭代器类
class Iterator {
public:
// 迭代器别名
using iterator_category = std::forward_iterator_tag;
using value_type = std::pair<const Key, T>;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
// 构造函数
Iterator(MyHashMap* map, size_type bucket_index, HashNode<Key, T>* node);
// 解引用操作符
reference operator*() const;
pointer operator->() const;
// 递增操作符
Iterator& operator++();
Iterator operator++(int);
// 比较操作符
bool operator==(const Iterator& other) const;
bool operator!=(const Iterator& other) const;
private:
MyHashMap* map_;
size_type bucket_index_;
HashNode<Key, T>* current_node_;
// 移动到下一个有效节点
void advance();
};
private:
std::vector<HashNode<Key, T>*> buckets_;
size_type bucket_count_;
size_type element_count_;
double max_load_factor_;
Hash hash_func_;
// 辅助函数
void rehash();
};

3. 基本操作实现#

构造函数及析构函数#

初始化哈希表,设置初始容量和负载因子。

// 构造函数
template <typename Key, typename T, typename Hash>
MyHashMap<Key, T, Hash>::MyHashMap(size_type initial_capacity, double max_load_factor)
: bucket_count_(initial_capacity),
element_count_(0),
max_load_factor_(max_load_factor),
hash_func_(Hash()) {
buckets_.resize(bucket_count_, nullptr);
}
// 析构函数
template <typename Key, typename T, typename Hash>
MyHashMap<Key, T, Hash>::~MyHashMap() {
clear();
}

插入(Insert)#

向哈希表中插入键值对。如果键已存在,则更新其值。

template <typename Key, typename T, typename Hash>
void MyHashMap<Key, T, Hash>::insert(const Key& key, const T& value) {
size_type hash_value = hash_func_(key);
size_type index = hash_value % bucket_count_;
HashNode<Key, T>* node = buckets_[index];
while (node != nullptr) {
if (node->data.first == key) {
node->data.second = value; // 更新值
return;
}
node = node->next;
}
// 键不存在,插入新节点到链表头部
HashNode<Key, T>* new_node = new HashNode<Key, T>(key, value);
new_node->next = buckets_[index];
buckets_[index] = new_node;
++element_count_;
// 检查负载因子,可能需要扩容
double load_factor = static_cast<double>(element_count_) / bucket_count_;
if (load_factor > max_load_factor_) {
rehash();
}
}

查找(Find)#

根据键查找对应的值,返回指向值的指针。如果未找到,则返回 nullptr

template <typename Key, typename T, typename Hash>
T* MyHashMap<Key, T, Hash>::find(const Key& key) {
size_type hash_value = hash_func_(key);
size_type index = hash_value % bucket_count_;
HashNode<Key, T>* node = buckets_[index];
while (node != nullptr) {
if (node->data.first == key) {
return &(node->data.second);
}
node = node->next;
}
return nullptr;
}
template <typename Key, typename T, typename Hash>
const T* MyHashMap<Key, T, Hash>::find(const Key& key) const {
size_type hash_value = hash_func_(key);
size_type index = hash_value % bucket_count_;
HashNode<Key, T>* node = buckets_[index];
while (node != nullptr) {
if (node->data.first == key) {
return &(node->data.second);
}
node = node->next;
}
return nullptr;
}

删除(Erase)#

根据键删除对应的键值对,返回删除是否成功。

template <typename Key, typename T, typename Hash>
bool MyHashMap<Key, T, Hash>::erase(const Key& key) {
size_type hash_value = hash_func_(key);
size_type index = hash_value % bucket_count_;
HashNode<Key, T>* node = buckets_[index];
HashNode<Key, T>* prev = nullptr;
while (node != nullptr) {
if (node->data.first == key) {
if (prev == nullptr) {
buckets_[index] = node->next;
} else {
prev->next = node->next;
}
delete node;
--element_count_;
return true;
}
prev = node;
node = node->next;
}
return false; // 未找到键
}

清空(Clear)#

删除哈希表中的所有元素,释放内存。

template <typename Key, typename T, typename Hash>
void MyHashMap<Key, T, Hash>::clear() {
for (size_type i = 0; i < bucket_count_; ++i) {
HashNode<Key, T>* node = buckets_[i];
while (node != nullptr) {
HashNode<Key, T>* temp = node;
node = node->next;
delete temp;
}
buckets_[i] = nullptr;
}
element_count_ = 0;
}

动态扩容(Rehashing)#

当负载因子超过阈值时,扩展哈希表容量并重新分配所有元素。

template <typename Key, typename T, typename Hash>
void MyHashMap<Key, T, Hash>::rehash() {
size_type new_bucket_count = bucket_count_ * 2;
std::vector<HashNode<Key, T>*> new_buckets(new_bucket_count, nullptr);
// 重新分配所有元素
for (size_type i = 0; i < bucket_count_; ++i) {
HashNode<Key, T>* node = buckets_[i];
while (node != nullptr) {
HashNode<Key, T>* next_node = node->next;
size_type new_index = hash_func_(node->data.first) % new_bucket_count;
// 插入到新桶的头部
node->next = new_buckets[new_index];
new_buckets[new_index] = node;
node = next_node;
}
}
// 替换旧桶
buckets_ = std::move(new_buckets);
bucket_count_ = new_bucket_count;
}

获取大小和状态#

template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::size_type MyHashMap<Key, T, Hash>::size() const {
return element_count_;
}
template <typename Key, typename T, typename Hash>
bool MyHashMap<Key, T, Hash>::empty() const {
return element_count_ == 0;
}

4. 迭代器的实现#

为了支持迭代器操作,使 MyHashMap 能够像标准容器一样被遍历,我们需要实现一个内部的 Iterator 类。

Iterator 类定义#

Iterator 类需要跟踪当前桶的索引和当前节点指针。它还需要能够找到下一个有效的节点。

// Iterator 构造函数
template <typename Key, typename T, typename Hash>
MyHashMap<Key, T, Hash>::Iterator::Iterator(MyHashMap* map, size_type bucket_index, HashNode<Key, T>* node)
: map_(map), bucket_index_(bucket_index), current_node_(node) {}
// 解引用操作符
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator::reference
MyHashMap<Key, T, Hash>::Iterator::operator*() const {
if (current_node_ == nullptr) {
throw std::out_of_range("Iterator out of range");
}
return current_node_->data;
}
// 成员访问操作符
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator::pointer
MyHashMap<Key, T, Hash>::Iterator::operator->() const {
if (current_node_ == nullptr) {
throw std::out_of_range("Iterator out of range");
}
return &(current_node_->data);
}
// 前置递增操作符
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator&
MyHashMap<Key, T, Hash>::Iterator::operator++() {
advance();
return *this;
}
// 后置递增操作符
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator
MyHashMap<Key, T, Hash>::Iterator::operator++(int) {
Iterator temp = *this;
advance();
return temp;
}
// 比较操作符==
template <typename Key, typename T, typename Hash>
bool MyHashMap<Key, T, Hash>::Iterator::operator==(const Iterator& other) const {
return map_ == other.map_ &&
bucket_index_ == other.bucket_index_ &&
current_node_ == other.current_node_;
}
// 比较操作符!=
template <typename Key, typename T, typename Hash>
bool MyHashMap<Key, T, Hash>::Iterator::operator!=(const Iterator& other) const {
return !(*this == other);
}
// advance 函数:移动到下一个有效节点
template <typename Key, typename T, typename Hash>
void MyHashMap<Key, T, Hash>::Iterator::advance() {
if (current_node_ != nullptr) {
current_node_ = current_node_->next;
}
while (current_node_ == nullptr && bucket_index_ + 1 < map_->bucket_count_) {
++bucket_index_;
current_node_ = map_->buckets_[bucket_index_];
}
}

迭代器操作#

MyHashMap 类中实现 begin()end() 函数来返回迭代器。

// begin() 函数
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator
MyHashMap<Key, T, Hash>::begin() {
for (size_type i = 0; i < bucket_count_; ++i) {
if (buckets_[i] != nullptr) {
return Iterator(this, i, buckets_[i]);
}
}
return end();
}
// end() 函数
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator
MyHashMap<Key, T, Hash>::end() {
return Iterator(this, bucket_count_, nullptr);
}

5. 完整代码示例#

以下是完整的 MyHashMap 实现,包括所有上述内容:

#include <vector>
#include <list>
#include <utility> // For std::pair
#include <functional> // For std::hash
#include <iterator> // For iterator_traits
#include <stdexcept> // For exceptions
#include <iostream>
// HashNode 结构定义
template <typename Key, typename T>
struct HashNode {
std::pair<const Key, T> data;
HashNode* next;
HashNode(const Key& key, const T& value)
: data(std::make_pair(key, value)), next(nullptr) {}
};
// MyHashMap 类定义
template <typename Key, typename T, typename Hash = std::hash<Key>>
class MyHashMap {
public:
// 迭代器类前向声明
class Iterator;
// 类型定义
using key_type = Key;
using mapped_type = T;
using value_type = std::pair<const Key, T>;
using size_type = size_t;
// 构造函数及析构函数
MyHashMap(size_type initial_capacity = 16, double max_load_factor = 0.75);
~MyHashMap();
// 禁止拷贝构造和赋值
MyHashMap(const MyHashMap&) = delete;
MyHashMap& operator=(const MyHashMap&) = delete;
// 基本操作
void insert(const Key& key, const T& value);
T* find(const Key& key);
const T* find(const Key& key) const;
bool erase(const Key& key);
size_type size() const;
bool empty() const;
void clear();
// 迭代器操作
Iterator begin();
Iterator end();
// 迭代器类
class Iterator {
public:
// 迭代器别名
using iterator_category = std::forward_iterator_tag;
using value_type = std::pair<Key, T>;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
// 构造函数
Iterator(MyHashMap* map, size_type bucket_index, HashNode<Key, T>* node);
// 解引用操作符
reference operator*() const;
pointer operator->() const;
// 递增操作符
Iterator& operator++();
Iterator operator++(int);
// 比较操作符
bool operator==(const Iterator& other) const;
bool operator!=(const Iterator& other) const;
private:
MyHashMap* map_;
size_type bucket_index_;
HashNode<Key, T>* current_node_;
// 移动到下一个有效节点
void advance();
};
private:
std::vector<HashNode<Key, T>*> buckets_;
size_type bucket_count_;
size_type element_count_;
double max_load_factor_;
Hash hash_func_;
// 辅助函数
void rehash();
};
// 构造函数
template <typename Key, typename T, typename Hash>
MyHashMap<Key, T, Hash>::MyHashMap(size_type initial_capacity, double max_load_factor)
: bucket_count_(initial_capacity),
element_count_(0),
max_load_factor_(max_load_factor),
hash_func_(Hash()) {
buckets_.resize(bucket_count_, nullptr);
}
// 析构函数
template <typename Key, typename T, typename Hash>
MyHashMap<Key, T, Hash>::~MyHashMap() {
clear();
}
// 插入函数
template <typename Key, typename T, typename Hash>
void MyHashMap<Key, T, Hash>::insert(const Key& key, const T& value) {
size_type hash_value = hash_func_(key);
size_type index = hash_value % bucket_count_;
HashNode<Key, T>* node = buckets_[index];
while (node != nullptr) {
if (node->data.first == key) {
node->data.second = value; // 更新值
return;
}
node = node->next;
}
// 键不存在,插入新节点到链表头部
HashNode<Key, T>* new_node = new HashNode<Key, T>(key, value);
new_node->next = buckets_[index];
buckets_[index] = new_node;
++element_count_;
// 检查负载因子,可能需要扩容
double load_factor = static_cast<double>(element_count_) / bucket_count_;
if (load_factor > max_load_factor_) {
rehash();
}
}
// 查找函数(非常量版本)
template <typename Key, typename T, typename Hash>
T* MyHashMap<Key, T, Hash>::find(const Key& key) {
size_type hash_value = hash_func_(key);
size_type index = hash_value % bucket_count_;
HashNode<Key, T>* node = buckets_[index];
while (node != nullptr) {
if (node->data.first == key) {
return &(node->data.second);
}
node = node->next;
}
return nullptr;
}
// 查找函数(常量版本)
template <typename Key, typename T, typename Hash>
const T* MyHashMap<Key, T, Hash>::find(const Key& key) const {
size_type hash_value = hash_func_(key);
size_type index = hash_value % bucket_count_;
HashNode<Key, T>* node = buckets_[index];
while (node != nullptr) {
if (node->data.first == key) {
return &(node->data.second);
}
node = node->next;
}
return nullptr;
}
// 删除函数
template <typename Key, typename T, typename Hash>
bool MyHashMap<Key, T, Hash>::erase(const Key& key) {
size_type hash_value = hash_func_(key);
size_type index = hash_value % bucket_count_;
HashNode<Key, T>* node = buckets_[index];
HashNode<Key, T>* prev = nullptr;
while (node != nullptr) {
if (node->data.first == key) {
if (prev == nullptr) {
buckets_[index] = node->next;
} else {
prev->next = node->next;
}
delete node;
--element_count_;
return true;
}
prev = node;
node = node->next;
}
return false; // 未找到键
}
// 清空函数
template <typename Key, typename T, typename Hash>
void MyHashMap<Key, T, Hash>::clear() {
for (size_type i = 0; i < bucket_count_; ++i) {
HashNode<Key, T>* node = buckets_[i];
while (node != nullptr) {
HashNode<Key, T>* temp = node;
node = node->next;
delete temp;
}
buckets_[i] = nullptr;
}
element_count_ = 0;
}
// 动态扩容函数
template <typename Key, typename T, typename Hash>
void MyHashMap<Key, T, Hash>::rehash() {
size_type new_bucket_count = bucket_count_ * 2;
std::vector<HashNode<Key, T>*> new_buckets(new_bucket_count, nullptr);
// 重新分配所有元素
for (size_type i = 0; i < bucket_count_; ++i) {
HashNode<Key, T>* node = buckets_[i];
while (node != nullptr) {
HashNode<Key, T>* next_node = node->next;
size_type new_index = hash_func_(node->data.first) % new_bucket_count;
// 插入到新桶的头部
node->next = new_buckets[new_index];
new_buckets[new_index] = node;
node = next_node;
}
}
// 替换旧桶
buckets_ = std::move(new_buckets);
bucket_count_ = new_bucket_count;
}
// begin() 函数
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator
MyHashMap<Key, T, Hash>::begin() {
for (size_type i = 0; i < bucket_count_; ++i) {
if (buckets_[i] != nullptr) {
return Iterator(this, i, buckets_[i]);
}
}
return end();
}
// end() 函数
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator
MyHashMap<Key, T, Hash>::end() {
return Iterator(this, bucket_count_, nullptr);
}
// Iterator 构造函数
template <typename Key, typename T, typename Hash>
MyHashMap<Key, T, Hash>::Iterator::Iterator(MyHashMap* map, size_type bucket_index, HashNode<Key, T>* node)
: map_(map), bucket_index_(bucket_index), current_node_(node) {}
// 解引用操作符
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator::reference
MyHashMap<Key, T, Hash>::Iterator::operator*() const {
if (current_node_ == nullptr) {
throw std::out_of_range("Iterator out of range");
}
return current_node_->data;
}
// 成员访问操作符
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator::pointer
MyHashMap<Key, T, Hash>::Iterator::operator->() const {
if (current_node_ == nullptr) {
throw std::out_of_range("Iterator out of range");
}
return &(current_node_->data);
}
// 前置递增操作符
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator&
MyHashMap<Key, T, Hash>::Iterator::operator++() {
advance();
return *this;
}
// 后置递增操作符
template <typename Key, typename T, typename Hash>
typename MyHashMap<Key, T, Hash>::Iterator
MyHashMap<Key, T, Hash>::Iterator::operator++(int) {
Iterator temp = *this;
advance();
return temp;
}
// 比较操作符==
template <typename Key, typename T, typename Hash>
bool MyHashMap<Key, T, Hash>::Iterator::operator==(const Iterator& other) const {
return map_ == other.map_ &&
bucket_index_ == other.bucket_index_ &&
current_node_ == other.current_node_;
}
// 比较操作符!=
template <typename Key, typename T, typename Hash>
bool MyHashMap<Key, T, Hash>::Iterator::operator!=(const Iterator& other) const {
return !(*this == other);
}
// advance 函数:移动到下一个有效节点
template <typename Key, typename T, typename Hash>
void MyHashMap<Key, T, Hash>::Iterator::advance() {
if(current_node_ != nullptr){
current_node_ = current_node_->next;
}
while(current_node_ == nullptr){
if(bucket_index_ +1 < map_->bucket_count_){
++bucket_index_;
current_node_ = map_->buckets_[bucket_index_];
}else if(bucket_index_ +1 == map_->bucket_count_){
++bucket_index_;
break;
}
}
}

6. 使用示例#

以下是一个使用 MyHashMap 的示例,展示如何插入、查找、删除以及使用迭代器遍历元素。

int main() {
MyHashMap<std::string, int> myMap;
// 插入元素
myMap.insert("apple", 3);
myMap.insert("banana", 5);
myMap.insert("orange", 2);
myMap.insert("grape", 7);
myMap.insert("cherry", 4);
// 使用迭代器遍历元素
std::cout << "Map contents:\n";
for(auto it = myMap.begin(); it != myMap.end(); ++it) {
std::cout << it->first << " => " << it->second << "\n";
}
// 查找元素
std::string keyToFind = "banana";
int* value = myMap.find(keyToFind);
if(value != nullptr) {
std::cout << "\nFound " << keyToFind << " with value: " << *value << "\n";
} else {
std::cout << "\n" << keyToFind << " not found.\n";
}
// 删除元素
myMap.erase("apple");
myMap.erase("cherry");
// 再次遍历
std::cout << "\nAfter erasing apple and cherry:\n";
for(auto it = myMap.begin(); it != myMap.end(); ++it) {
std::cout << it->first << " => " << it->second << "\n";
}
return 0;
}

预期输出#

Map contents:
cherry => 4
banana => 5
apple => 3
grape => 7
orange => 2
Found banana with value: 5
After erasing apple and cherry:
banana => 5
grape => 7
orange => 2

注意:由于哈希表的桶顺序依赖于哈希函数的实现,输出顺序可能与预期有所不同。

Hash() 在上述 MyHashMap 实现中是一个哈希函数对象。让我们详细解释一下它的含义以及它在代码中的作用。

Hash 是什么?#

MyHashMap 的模板定义中,Hash 是一个模板参数,用于指定键类型 Key 的哈希函数。它有一个默认值 std::hash<Key>,这意味着如果用户在实例化 MyHashMap 时没有提供自定义的哈希函数,std::hash<Key> 将被使用。

template <typename Key, typename T, typename Hash = std::hash<Key>>
class MyHashMap {
// ...
};

默认情况下:std::hash<Key>#

std::hash 是 C++ 标准库(STL)中提供的一个模板结构,用于为各种内置类型(如 int, std::string 等)生成哈希值。std::hash<Key> 会根据 Key 的类型自动选择合适的哈希函数实现。

例如:

  • 对于 int 类型,std::hash<int> 会生成一个简单的哈希值。
  • 对于 std::string 类型,std::hash<std::string> 会基于字符串内容生成哈希值。
std::hash<int> intHasher;
size_t hashValue = intHasher(42); // 生成整数 42 的哈希值
std::hash<std::string> stringHasher;
size_t stringHash = stringHasher("hello"); // 生成字符串 "hello" 的哈希值

自定义哈希函数#

除了使用 std::hash,用户还可以自定义哈希函数,以适应特定的需求或优化性能。例如,假设你有一个自定义的键类型 Point

struct Point {
int x;
int y;
bool operator==(const Point& other) const {
return x == other.x && y == other.y;
}
};

你可以定义一个自定义的哈希函数 PointHasher

struct PointHasher {
size_t operator()(const Point& p) const {
// 简单的哈希组合,实际应用中应选择更好的哈希组合方法
return std::hash<int>()(p.x) ^ (std::hash<int>()(p.y) << 1);
}
};

然后,在实例化 MyHashMap 时使用自定义哈希函数:

MyHashMap<Point, std::string, PointHasher> pointMap;
Point p1{1, 2};
pointMap.insert(p1, "Point1");

Hash() 在代码中的作用#

MyHashMap 的构造函数中,Hash() 用于实例化哈希函数对象,并将其赋值给成员变量 hash_func_

// 构造函数
template <typename Key, typename T, typename Hash>
MyHashMap<Key, T, Hash>::MyHashMap(size_type initial_capacity, double max_load_factor)
: bucket_count_(initial_capacity),
element_count_(0),
max_load_factor_(max_load_factor),
hash_func_(Hash()) { // 这里的 Hash() 是一个默认构造函数调用
buckets_.resize(bucket_count_, nullptr);
}

具体作用:#

  1. 实例化哈希函数对象
    • Hash() 会调用 Hash 类型的默认构造函数,创建一个哈希函数对象。
    • 如果 Hashstd::hash<Key>,那么就创建一个 std::hash<Key> 对象。
  2. 存储哈希函数对象
    • 生成的哈希函数对象被存储在成员变量 hash_func_ 中,以便在哈希表的各种操作(如插入、查找、删除)中使用。
  3. 支持不同的哈希函数
    • 由于 Hash 是一个模板参数,可以灵活地使用不同的哈希函数,无需修改 MyHashMap 的内部实现。

示例代码解释#

以下是相关部分的简化示例,帮助理解 HashHash() 的作用:

#include <vector>
#include <functional> // For std::hash
template <typename Key, typename T, typename Hash = std::hash<Key>>
class MyHashMap {
public:
MyHashMap(size_t initial_capacity = 16, double max_load_factor = 0.75)
: bucket_count_(initial_capacity),
element_count_(0),
max_load_factor_(max_load_factor),
hash_func_(Hash()) { // 实例化哈希函数对象
buckets_.resize(bucket_count_, nullptr);
}
void insert(const Key& key, const T& value) {
size_t hash_value = hash_func_(key); // 使用哈希函数对象
size_t index = hash_value % bucket_count_;
// 插入逻辑...
}
private:
std::vector<HashNode<Key, T>*> buckets_;
size_t bucket_count_;
size_t element_count_;
double max_load_factor_;
Hash hash_func_; // 存储哈希函数对象
};

总结#

  • Hash** 是模板参数**,用于指定键类型 Key 的哈希函数。默认情况下,它使用 C++ 标准库中的 std::hash<Key>
  • Hash()** 是一个默认构造函数调用**,用于实例化哈希函数对象,并将其存储在 hash_func_ 成员变量中,以便在哈希表操作中使用。
  • 用户可以自定义哈希函数,通过提供自定义的哈希函数对象,实现对特定键类型的优化或满足特殊需求。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

无序map封装
https://godze.online/posts/c-plus-plus/无序map封装/
作者
Vafail
发布于
2026-05-27
许可协议
CC BY-NC-SA 4.0

评论区

公告
欢迎来到我的博客!
分类
标签
最新动态
站点统计
文章
61
分类
6
标签
8
总字数
136,467
运行时长
0
最后活动
0 天前
站点信息
构建平台
Vercel
博客版本
Firefly v6.15.3
文章许可
CC BY-NC-SA 4.0