C++ 入门第 20 天:STL 容器之无序集合与无序多重集合
往期回顾:
C++ 入门17:STL 容器之映射(map)与多重映射(multimap)_-CSDN博客
C++ 入门18:STL 容器之栈(stack)与队列(queue)-CSDN博客
C++ 入门19:STL 容器之优先队列(priority_queue)-CSDN博客
C++ 入门第 20 天:STL 容器之无序集合与无序多重集合
一、前言
在之前的学习中,我们已经掌握了 set
和 multiset
容器,它们都是有序关联容器。但在某些场景下,我们并不关心元素的顺序,而是追求更高的性能。在这种情况下,C++ 提供了 无序容器,例如 unordered_set
和 unordered_multiset
,它们的底层基于 哈希表(Hash Table) 实现,能够以常数时间完成插入、删除和查找操作。
1. 无序集合(unordered_set)
unordered_set
是一个 无序关联容器,用于存储不重复的元素。与 set
不同,unordered_set
的元素没有顺序,它的主要特点是:
- 底层实现:基于哈希表,操作效率高。
- 唯一性:不允许重复元素。
- 平均时间复杂度:插入、删除、查找的时间复杂度为 O(1)O(1)O(1)。
1.1 基本操作
以下是 unordered_set
的常用操作:
成员函数 | 功能说明 |
insert(value) | 插入元素 |
erase(value) | 删除指定元素 |
find(value) | 查找元素,返回迭代器 |
count(value) | 检查某元素是否存在(返回 0 或 1) |
size() | 获取元素个数 |
empty() | 检查容器是否为空 |
示例代码:基本操作
#include <iostream>
#include <unordered_set>
using namespace std;int main() {// 定义一个无序集合unordered_set<int> us;// 插入元素us.insert(10);us.insert(20);us.insert(30);us.insert(10); // 重复元素将被忽略// 遍历集合cout << "Elements in unordered_set: ";for (int elem : us) {cout << elem << " ";}cout << endl;// 查找元素if (us.find(20) != us.end()) {cout << "Element 20 is found in the unordered_set." << endl;}// 删除元素us.erase(10);cout << "After removing 10, elements in unordered_set: ";for (int elem : us) {cout << elem << " ";}cout << endl;return 0;
}
注意:输出的元素顺序与插入顺序无关,因为 unordered_set
使用哈希表存储数据。
1.2 哈希表的特性
无序集合通过哈希函数将值映射到特定的存储位置。哈希表的效率依赖于:
- 哈希函数:将值映射到存储位置。
- 装载因子(load factor):当前元素数量与桶数量的比值。过高时,哈希表会进行重新哈希(rehash)。
我们可以通过以下函数查看或修改哈希表的状态:
成员函数 | 功能说明 |
bucket_count() | 返回桶的数量 |
load_factor() | 返回装载因子 |
max_load_factor(f) | 设置装载因子的上限 |
rehash(n) | 强制重新哈希并至少设置 n 个桶 |
示例代码:查看哈希表状态
#include <iostream>
#include <unordered_set>
using namespace std;int main() {unordered_set<int> us = {10, 20, 30};cout << "Bucket count: " << us.bucket_count() << endl;cout << "Load factor: " << us.load_factor() << endl;// 强制重新哈希us.rehash(20);cout << "After rehash, bucket count: " << us.bucket_count() << endl;return 0;
}
2. 无序多重集合(unordered_multiset)
unordered_multiset
与 unordered_set
类似,不同点是:
- 允许重复元素:可以插入多个值相同的元素。
- 哈希表存储:仍然基于哈希表实现。
2.1 基本操作
unordered_multiset
的常用操作与 unordered_set
类似,但允许重复元素:
成员函数 | 功能说明 |
insert(value) | 插入元素 |
erase(value) | 删除指定元素 |
count(value) | 返回某元素出现的次数 |
示例代码:无序多重集合
#include <iostream>
#include <unordered_set>
using namespace std;int main() {// 定义一个无序多重集合unordered_multiset<int> ums;// 插入元素ums.insert(10);ums.insert(20);ums.insert(10); // 允许重复// 遍历集合cout << "Elements in unordered_multiset: ";for (int elem : ums) {cout << elem << " ";}cout << endl; // 输出:10 20 10(顺序可能不同)// 查询某元素的出现次数cout << "Count of 10: " << ums.count(10) << endl;// 删除某个值的所有实例ums.erase(10);cout << "After removing 10, elements in unordered_multiset: ";for (int elem : ums) {cout << elem << " ";}cout << endl;return 0;
}
3. unordered_set
和 unordered_multiset
的性能分析
优点
- 高效:基于哈希表实现,插入、删除、查找的平均时间复杂度为 O(1)O(1)O(1)。
- 灵活:支持快速查找和重复值存储。
缺点
- 顺序无保证:无法保证元素存储顺序,适合只关心内容的场景。
- 哈希冲突:当冲突较多时,性能可能下降,接近 O(n)O(n)O(n)。
对比:set
vs unordered_set
特性 | set | unordered_set |
底层结构 | 红黑树 | 哈希表 |
是否有序 | 有序 | 无序 |
查找时间复杂度 | O(logn)O(\log n)O(logn) | O(1)O(1)O(1)(平均情况) |
插入、删除时间复杂度 | O(logn)O(\log n)O(logn) | O(1)O(1)O(1)(平均情况) |
4. 实际应用场景
- 去重:
unordered_set
适合需要去重但不关心顺序的场景,例如统计某一组数据中不重复的值。 - 频率统计:
unordered_multiset
可以用来统计某些值的出现次数。 - 高效查找:在大规模数据中快速查找是否存在某元素。
示例:统计字符串中单词出现次数
使用
unordered_multiset
来统计一个字符串中单词的频率。示例代码
#include <iostream> #include <unordered_set> #include <sstream> #include <string> using namespace std;int main() {string text = "hello world hello C++ world";unordered_multiset<string> wordCount;// 将字符串分割为单词stringstream ss(text);string word;while (ss >> word) {wordCount.insert(word);}// 输出每个单词的出现次数for (const string& w : wordCount) {cout << w << ": " << wordCount.count(w) << endl;wordCount.erase(w); // 删除已处理的单词}return 0; }
结语
以上就是 C++ 标准模板库中的无序集合与无序多重集合的基础知识点了。这些无序容器通过哈希表实现,能够提供极高的操作效率,适用于需要快速查找、插入和删除的场景。掌握无序集合与无序多重集合的使用,基本上在开发中都会用到的,大家多看看,一定要掌握。
-
都看到这里了,点个赞再走呗朋友~
-
加油吧,预祝大家变得更强!