更多 C++语法知识在 C++语言学记专栏
往期 STL 容器看点:
这篇文章是关于 C++所有数据结构概览中的单独专题
顺序容器 vector array list deque forward_list 关联容器 set&multiset map&multimap 无序关联容器 Unordered set&multiset Unordered map&multimap 容器适配器 stack queue priority_queue 其他容器 string
C++ STL: unordered_set 与 unordered_multiset 详解
核心概念
std::unordered_set 和 std::unordered_multiset 是 C++11 标准引入的关联容器。与我们之前讨论的 set 和 multiset 不同,它们内部不是基于红黑树,而是基于哈希表 (Hash Table) 来实现的。
这个根本性的结构差异带来了它们最显著的特点:
-
无序性 (Unordered): 顾名思义,容器内的元素不会自动排序。元素的存储位置由其哈希值决定,遍历它们时得到的顺序通常是无意义的,且可能在程序每次运行时都不同。
-
极高的性能: 由于哈希表的特性,这些容器在插入、删除和查找操作上的平均时间复杂度为常数时间 O(1)。这是它们相比于
set(O(logN))的最大优势。 -
最坏情况: 在极罕见的哈希碰撞严重的情况下,性能可能退化到线性时间 O(N)。但在实践中,只要哈希函数设计良好,这种情况很少发生。
哈希表工作原理简介
-
哈希函数 (Hash Function): 当你向容器中插入一个元素时,容器会使用一个哈希函数(默认是
std::hash)将元素的值转换成一个整数,即哈希值 (hash value)。 -
桶 (Buckets): 哈希表内部由一个称为“桶”的数组构成。上一步计算出的哈希值被用来决定元素应该放入哪个桶中。
-
哈希碰撞 (Hash Collision): 有可能两个不同的元素计算出相同的哈希值,导致它们需要被放入同一个桶中。哈希表有解决碰撞的机制(如链地址法),但这会导致性能下降。
-
等价性判断 (Equivalence): 对于放入同一个桶中的元素,容器会使用元素的
operator==来判断它们是否相等。因此,要存入无序容器的自定义类型必须同时提供哈希函数和等价性比较操作。
主要区别
unordered_set 和 unordered_multiset 的区别与它们的有序版本完全相同:是否允许存储重复的元素。
-
std::unordered_set: 元素必须唯一。 -
std::unordered_multiset: 元素可以重复。
std::unordered_set 详解
unordered_set 是一个存储唯一元素的集合,当你需要极快的元素存在性检查而不在乎其顺序时,它是理想的选择。
头文件:
#include <unordered_set>
特性
-
唯一性: 插入重复元素会被忽略。
-
无序: 元素存储和遍历顺序不固定。
-
快速: 平均 O(1) 的插入、删除和查找。
语法与常用操作
unordered_set 的接口与 set 非常相似,但没有提供与排序相关的函数(如 lower_bound, upper_bound)。
1. 构造与修改器
-
构造函数、
insert,emplace,erase,clear,swap等函数的使用方法与std::set基本一致。 -
insert(value)的返回值依然是std::pair<iterator, bool>,bool值表示是否插入成功。
2. 查找 (Lookup)
-
find(value): 查找元素。平均 O(1)。 -
count(value): 检查元素是否存在。返回 0 或 1,平均 O(1)。
- 哈希策略 (Bucket Interface)
这些是哈希容器特有的函数,用于观察和控制哈希表的内部状态。
-
bucket_count(): 返回当前的桶数。 -
load_factor(): 返回当前的加载因子(size() / bucket_count())。加载因子越大,碰撞的可能性越高。 -
max_load_factor(z): 获取或设置最大加载因子。当实际加载因子超过这个值时,容器会自动增加桶数并重新哈希(rehash)所有元素。 -
rehash(n): 手动请求将桶数增加到至少n。
std::unordered_set 示例代码
#include <iostream>
#include <unordered_set>
#include <string>
int main() {
// 1. 创建和初始化
std::unordered_set<std::string> fruit_set;
// 2. 插入元素
fruit_set.insert

503

被折叠的 条评论
为什么被折叠?



