std::unordered_map
std::unordered_map 是 C++ 标准库中的一个无序关联容器,用于存储键值对(key-value)。与 std::map 不同的是,unordered_map 内部使用 哈希表 来组织元素,因此元素的顺序不固定,完全由哈希函数决定。
它能在平均 O(1) 时间内完成查找、插入和删除操作(最坏情况下退化为 O(n))。
unordered_map 的定义如下:
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>
> class unordered_map; // since C++11
namespace pmr {
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>
> using unordered_map =
std::unordered_map<Key, T, Hash, KeyEqual,
std::pmr::polymorphic_allocator<std::pair<const Key, T>>>;
} // since C++17
- Key:键的类型(必须支持哈希和比较相等操作)。
- T:映射值的类型。
- Hash:哈希函数对象,默认为
std::hash<Key>。 - Pred:相等比较函数对象,默认为
std::equal_to<Key>。 - Alloc:分配器类型,默认为
std::allocator<std::pair<const Key, T>>。
1. 引入
#include <unordered_map>
2. 存储方式
std::map使用 红黑树,有序,查找/插入/删除是 O(log n)。std::unordered_map使用 哈希表,无序,查找/插入/删除平均是 O(1),但在哈希冲突严重时,最坏情况可能退化为 O(n)。
每个键值对通过哈希函数映射到某个 桶(bucket) 中,冲突时使用链表或开链方式解决。 键必须唯一,如果插入相同的键,新值会覆盖旧值。
3. 方法
(1) 构造方法
-
unordered_map(): 默认构造函数std::unordered_map<int, std::string> m; std::unordered_map<int, std::string> m = {{1, "one"}, {2, "two"}}; -
unordered_map(const unordered_map&): 复制构造函数std::unordered_map<int, std::string> m1 = {{1, "one"}, {2, "two"}}; std::unordered_map<int, std::string> m2(m1); -
unordered_map(begin, end): 使用另一个容器或迭代器的区间中的元素初始化std::vector<std::pair<int, std::string>> vec = {{1, "one"}, {2, "two"}}; std::unordered_map<int, std::string> m(vec.begin(), vec.end()); -
std::unordered_map<key, T, Compare>: 使用自定义的比较器来进行键的排序struct MyHash { size_t operator()(int x) const { return x % 10; } }; std::unordered_map<int, std::string, MyHash> m;
(2) 大小函数
size_t size() const: 返回元素个数bool empty() const: 是否为空size_t max_size() const: 返回最大可允许元素数量void reserve(size_type __n): 预分配桶的数量,减少扩容开销
(3) 增加函数
-
std::pair<iterator, bool> insert(const value_type& __x): 插入一个键值对,返回保存指向添加键值对位置的迭代器和是否添加成功的标志的pairm.insert({1, "one"}); m.insert(std::make_pair(2, "two")); -
std::pair<iterator, bool> emplace(Key&& key, T&& obj): 如果键 key 不存在,就直接插入一个新元素。m.emplace(3, "three"); -
std::pair<iterator, bool> try_emplace(const Key& key, Args&&... args): 只有在 key 不存在时,才插入新元素(避免额外的拷贝)。m.try_emplace(1, "one"); -
std::pair<iterator, bool> insert_or_assign(const Key& key, T&& obj)m.insert_or_assign(1, "uno"); -
operator[](const Key& key): 如果 key 存在,返回对应的值;如果 key 不存在,插入一个新的键值对,值为默认构造的类型 T。m[4] = "four"; // 插入 m[1] = "uno"; // 更新 -
at(const Key& key):如果 key 已存在,更新对应的值;如果 key 不存在,插入一个新的键值对。std::cout << m.at(1);
(4) 删除元素
void clear():清空所有元素iterator erase(iterator pos):删除迭代器位置的元素iterator erase(const key_type& key):删除指定键,返回删除个数iterator erase(first, last):删除范围
(5) 查找函数
-
iterator find(const key_type& key): 查找某个键在unordered_map中的位置,返回一个指向该元素的迭代器,如果找不到会返回end()。std::unordered_map<int, std::string> m = {{1, "one"}, {2, "two"}}; auto it = m.find(1); // 返回指向键1的迭代器 std::cout << it->second; // 输出 "one" -
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const: 返回一对迭代器,表示所有具有等于键key的元素的范围。在std::unordered_map中,由于键是唯一的,因此这个范围包含一个元素。std::unordered_map<int, std::string> m = {{1, "one"}, {2, "two"}}; auto range = m.equal_range(1); std::cout << range.first->second << std::endl; // 输出 "one" -
size_t count(const key_type& key): 返回容器中是否包含指定键,unordered_map中每个键最多出现一次,因此返回值要么是0,要么是1。 -
iterator lower_bound(const key_type& key): 返回第一个不小于key的迭代器。 -
iterator upper_bound(const key_type& key): 返回第一个大于key的迭代器。 -
bool contains(const key_type& key) const(C++20):检查是否包含该键。
(6) 遍历函数
-
iterator begin(): 返回指向std::unordered_map第一个元素的迭代器。std::unordered_map<int, std::string> m = {{1, "one"}, {2, "two"}}; auto it = m.begin(); // 返回指向第一个元素的迭代器 std::cout << it->first << ": " << it->second << std::endl; // 输出 1: one -
iterator end(): 返回指向std::unordered_map最后一个元素之后位置的迭代器。 -
reverse_iterator rbegin(): 返回指向std::unordered_map最后一个元素的反向迭代器。 -
reverse_iterator rend(): 返回指向std::unordered_map第一个元素之前位置的反向迭代器。 -
使用基于范围的
for循环(C++11 及以上): 直接遍历std::unordered_map中的每个元素。std::unordered_map<int, std::string> m = {{1, "one"}, {2, "two"}}; for (const auto& pair : m) { std::cout << pair.first << ": " << pair.second << " "; // 输出: 1: one 2: two } -
使用传统的
for循环(基于迭代器): 使用迭代器来遍历std::unordered_map。std::unordered_map<int, std::string> m = {{1, "one"}, {2, "two"}}; for (auto it = m.begin(); it != m.end(); ++it) { std::cout << it->first << ": " << it->second << " "; // 输出: 1: one 2: two }
(7) 哈希相关函数
-
size_type max_bucket_count() const noexcept: max_bucket_count() 返回 std::unordered_set 中可用的最大哈希桶数量。哈希表是由一组桶(bucket)构成的,每个桶存储一定数量的元素。当元素的数量增加时,std::unordered_set 可能会自动扩展桶的数量,以减少哈希冲突。max_bucket_count() 允许你查看哈希表最多能支持多少个桶。 -
float max_load_factor() const noexcept: max_load_factor() 返回或设置哈希表的最大负载因子。负载因子是哈希表中元素的数量与桶数量之比。它决定了哈希表何时扩展——当负载因子超过最大值时,std::unordered_set 会增加桶的数量,减少哈希冲突,从而提高性能。- 负载因子是指:负载因子 = 元素个数 / 桶的数量
- 最大负载因子是哈希表在扩展之前允许的最大负载因子。负载因子越高,意味着桶的数量相对较少,这可能导致更多的哈希冲突,降低查找效率。
-
void max_load_factor(float __z): 设置最大负载因子。 -
size_t bucket_count() const: 返回当前 unordered_set 的桶数量。哈希表的桶数量与容器中元素的数量以及负载因子相关,通常哈希表会在元素数量增加时自动扩展桶的数量。 -
size_t bucket_size(size_t n) const: 返回指定桶的元素数量。哈希表中的每个桶可能包含多个元素,特别是当哈希冲突发生时,多个元素可能会存储在同一个桶中。 -
size_t bucket(const key_type& key) const: 返回给定键所在的桶的索引。这个函数对于理解元素是如何分布在哈希表中的非常有用。 -
float load_factor() const: 返回当前哈希表的负载因子,即元素的数量与桶数量的比值。负载因子越高,哈希冲突的可能性越大,因此负载因子对于性能非常重要。 -
void rehash(size_t n): 用来调整哈希表中的桶数量。它的作用是根据新的元素数量来调整桶的数量,避免哈希冲突过多。rehash() 会导致重新分配桶并重新哈希元素。n 是希望容器能够容纳的元素数量。
(8) 其他函数
-
swap(unordered_map& other): 交换当前std::unordered_map和另一个std::unordered_map的内容。 -
std::allocator<T> get_allocator() const: 返回容器所使用的分配器(allocator)。 -
void merge(unordered_map& other):merge会将另一个 unordered_map 中不与当前容器重复的元素“移动”过来。std::unordered_map<int> s1 = {1, 3, 5}; std::unordered_map<int> s2 = {2, 4, 6}; s1.merge(s2); // s1 合并 s2 后,变为 {1, 2, 3, 4, 5, 6} -
key_equal_type key_eq() const: 返回一个比较器,用于判断两个键是否相等std::unordered_map<Person, PersonHash> people; Person p1 = {"Alice", 30}; Person p2 = {"Bob", 25}; people.insert(p1); people.insert(p2); // 使用 key_eq 获取比较函数 auto eq = people.key_eq(); // 使用 key_eq 函数比较两个键 std::cout << "Are p1 and p2 equal? " << std::boolalpha << eq(p1, p2) << std::endl; -
hasher hash_function() const:返回当前使用的哈希函数对象