110 std::unordered_multiset (哈希表)


作者Lou Xiao, deepseek创建时间2025-04-02 17:44:58更新时间2025-04-02 17:44:58

1. 概述

  • 定义std::unordered_multiset 是 C++ STL 中的关联容器,允许存储重复的元素,基于哈希表实现。
  • 特点
  • 无序性:元素不按特定顺序存储(与 std::multiset 的有序性对比)。
  • 允许重复键:不同于 std::unordered_set,可以插入多个相同值的元素。
  • 平均时间复杂度:插入、删除、查找操作的平均复杂度为 O(1),最坏情况 O(n)(哈希冲突时)。

2. 头文件与声明

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <unordered_set>
2 using namespace std;
3
4 unordered_multiset<int> ums; // 声明一个存储int的无序多重集合

3. 模板参数

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 template<
2 class Key,
3 class Hash = std::hash<Key>,
4 class KeyEqual = std::equal_to<Key>,
5 class Allocator = std::allocator<Key>
6 > class unordered_multiset;
  • Key:元素类型。
  • Hash:哈希函数对象(默认 std::hash<Key>)。
  • KeyEqual:键比较函数(默认 std::equal_to<Key>)。
  • Allocator:内存分配器(通常无需修改)。

4. 核心操作

操作语法说明
插入元素ums.insert(value)插入一个元素(允许重复)。
删除元素ums.erase(value)删除所有匹配的 value
查找元素ums.find(value)返回首个匹配的迭代器,无则返回 end()
计数元素ums.count(value)返回 value 的出现次数。
判断空容器ums.empty()返回是否为空。
获取元素数量ums.size()返回元素总数(包括重复)。
清空容器ums.clear()移除所有元素。

5. 迭代器与遍历

  • 迭代器类型:前向迭代器(begin(), end(), cbegin(), cend())。
  • 遍历示例
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 for (auto it = ums.begin(); it != ums.end(); ++it) {
2 cout << *it << " ";
3 }
4 // 或使用范围for循环
5 for (const auto& val : ums) {
6 cout << val << " ";
7 }

6. 桶管理(Bucket Interface)

  • 哈希表特性:元素被分配到不同的桶中。
  • 关键操作
  • bucket_count():返回桶的总数。
  • bucket_size(n):返回第 n 个桶的元素数量。
  • bucket(key):返回 key 所在的桶索引。

7. 哈希策略

  • 负载因子(Load Factor):size() / bucket_count()
  • load_factor():返回当前负载因子。
  • max_load_factor():获取/设置最大负载因子(触发重哈希的阈值)。
  • 重哈希
  • rehash(n):将桶数量调整为至少 n
  • reserve(n):预留空间以避免重复重哈希。

8. 示例代码

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <iostream>
2 #include <unordered_set>
3
4 int main() {
5 std::unordered_multiset<int> ums = {1, 2, 3, 2, 4};
6
7 ums.insert(2); // 插入重复元素
8 ums.erase(3); // 删除所有值为3的元素
9
10 std::cout << "Count of 2: " << ums.count(2) << std::endl; // 输出3
11
12 for (int val : ums) {
13 std::cout << val << " "; // 输出顺序不确定,如:1 4 2 2 2
14 }
15 }

9. 与 std::multiset 对比

特性std::unordered_multisetstd::multiset
底层结构哈希表红黑树(平衡二叉搜索树)
顺序性无序有序(默认升序)
时间复杂度平均 O(1),最坏 O(n)插入/查找/删除均为 O(log n)
自定义排序不支持(依赖哈希)支持(通过 Compare 模板参数)

10. 注意事项

  • 哈希冲突:性能可能因哈希函数质量下降。
  • 迭代器失效
  • 插入操作可能导致重哈希,使所有迭代器失效。
  • 删除操作仅使被删除元素的迭代器失效。
  • 自定义类型:需提供自定义 HashKeyEqual 函数对象。

11. 进阶用法

自定义哈希函数

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 struct MyHash {
2 size_t operator()(const MyClass& obj) const {
3 return std::hash<int>()(obj.key);
4 }
5 };
6 std::unordered_multiset<MyClass, MyHash> customSet;

性能优化:通过 reserve() 预分配空间减少重哈希次数。


std::unordered_multiset

名称用途原型代码示例注释
构造函数创建无序多重集合unordered_multiset<Key, Hash, KeyEqual, Allocator>::unordered_multiset(...)std::unordered_multiset<int> nums = {1, 2, 2, 3};支持默认构造、范围构造、拷贝构造等。
insert插入元素(允许重复)iterator insert(const value_type& value);nums.insert(4);返回指向插入元素的迭代器。
emplace直接构造元素(避免拷贝)template <class... Args> iterator emplace(Args&&... args);nums.emplace(5);效率可能高于 insert
erase删除元素iterator erase(iterator pos);
size_type erase(const key_type& key);
nums.erase(2);
nums.erase(nums.begin());
按值删除会移除所有匹配项,返回删除数量;按迭代器删除返回下一个迭代器。
clear清空容器void clear() noexcept;nums.clear();容器大小变为 0。
find查找元素iterator find(const key_type& key);auto it = nums.find(3);返回首个匹配的迭代器,未找到时返回 end()
count统计元素出现次数size_type count(const key_type& key) const;size_t n = nums.count(2);返回键值 key 的出现次数(可能 > 1)。
equal_range返回匹配元素的范围std::pair<iterator, iterator> equal_range(const key_type& key);auto [first, last] = nums.equal_range(2);返回包含所有匹配元素的迭代器范围。
size返回元素数量size_type size() const noexcept;size_t s = nums.size();包括所有重复元素。
empty检查容器是否为空bool empty() const noexcept;if (nums.empty()) { ... }等价于 size() == 0
bucket_count返回桶的数量size_type bucket_count() const noexcept;size_t bc = nums.bucket_count();哈希表内部的桶数。
load_factor返回当前负载因子(元素数/桶数)float load_factor() const noexcept;float lf = nums.load_factor();负载因子过高时可能触发 rehash。
rehash设置桶的数量void rehash(size_type n);nums.rehash(20);调整桶数以适应至少 n 个元素。
begin/end返回迭代器iterator begin() noexcept;
iterator end() noexcept;
for (auto it = nums.begin(); it != nums.end(); ++it)支持常量迭代器 cbegin()/cend()

示例代码(综合使用)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <iostream>
2 #include <unordered_set>
3
4 int main() {
5 std::unordered_multiset<int> nums = {1, 2, 2, 3};
6
7 // 插入元素
8 nums.insert(4);
9 nums.emplace(5);
10
11 // 查找与统计
12 if (nums.find(3) != nums.end()) {
13 std::cout << "Found 3, count: " << nums.count(3) << std::endl;
14 }
15
16 // 删除元素
17 nums.erase(2); // 删除所有值为2的元素
18
19 // 遍历
20 for (int num : nums) {
21 std::cout << num << " ";
22 }
23
24 return 0;
25 }

注释说明

  1. 允许重复:与 unordered_set 不同,unordered_multiset 允许存储相同键值的元素。
  2. 哈希冲突:元素通过哈希函数分配到桶中,冲突时通过链表存储。
  3. 迭代器失效:插入或删除操作可能导致迭代器失效(除非是当前元素的 erase 返回的迭代器)。
文章目录