当前位置: 首页 > news >正文

C++ 入门第 20 天:STL 容器之无序集合与无序多重集合

往期回顾:

C++ 入门17:STL 容器之映射(map)与多重映射(multimap)_-CSDN博客

C++ 入门18:STL 容器之栈(stack)与队列(queue)-CSDN博客

C++ 入门19:STL 容器之优先队列(priority_queue)-CSDN博客


 C++ 入门第 20 天:STL 容器之无序集合与无序多重集合

一、前言

在之前的学习中,我们已经掌握了 setmultiset 容器,它们都是有序关联容器。但在某些场景下,我们并不关心元素的顺序,而是追求更高的性能。在这种情况下,C++ 提供了 无序容器,例如 unordered_setunordered_multiset,它们的底层基于 哈希表(Hash Table) 实现,能够以常数时间完成插入、删除和查找操作。

1. 无序集合(unordered_set)

unordered_set 是一个 无序关联容器,用于存储不重复的元素。与 set 不同,unordered_set 的元素没有顺序,它的主要特点是:

  1. 底层实现:基于哈希表,操作效率高。
  2. 唯一性:不允许重复元素。
  3. 平均时间复杂度:插入、删除、查找的时间复杂度为 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 哈希表的特性

无序集合通过哈希函数将值映射到特定的存储位置。哈希表的效率依赖于:

  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_multisetunordered_set 类似,不同点是:

  1. 允许重复元素:可以插入多个值相同的元素。
  2. 哈希表存储:仍然基于哈希表实现。

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_setunordered_multiset 的性能分析

优点

  1. 高效:基于哈希表实现,插入、删除、查找的平均时间复杂度为 O(1)O(1)O(1)。
  2. 灵活:支持快速查找和重复值存储。

缺点

  1. 顺序无保证:无法保证元素存储顺序,适合只关心内容的场景。
  2. 哈希冲突:当冲突较多时,性能可能下降,接近 O(n)O(n)O(n)。

对比:set vs unordered_set

特性setunordered_set
底层结构红黑树哈希表
是否有序有序无序
查找时间复杂度O(log⁡n)O(\log n)O(logn)O(1)O(1)O(1)(平均情况)
插入、删除时间复杂度O(log⁡n)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++ 标准模板库中的无序集合与无序多重集合的基础知识点了。这些无序容器通过哈希表实现,能够提供极高的操作效率,适用于需要快速查找、插入和删除的场景。掌握无序集合与无序多重集合的使用,基本上在开发中都会用到的,大家多看看,一定要掌握。

  • 都看到这里了,点个赞再走呗朋友~

  • 加油吧,预祝大家变得更强!

http://www.lryc.cn/news/506129.html

相关文章:

  • devops-部署Harbor实现私有Docker镜像仓库
  • rebase ‘A‘ onto ‘master‘ 和 merge ‘master‘ into ‘A‘有什么区别
  • Vulhub:Jackson[漏洞复现]
  • strongswan构建测试环境
  • 前端:金额高精度处理
  • 面试题整理3----nc命令的常见用法
  • Trimble天宝三维激光扫描仪在建筑工程竣工测量中的应用【沪敖3D】
  • IntelliJ IDEA 使用技巧与插件推荐
  • Oracle 技术精选学习
  • sqlilabs第三十关到第三十五关靶场攻略
  • windows免登录linux
  • matlab绘图时设置左、右坐标轴为不同颜色
  • springboot+javafx使用aop切面导致的fx:id不能被注入问题
  • 说说你对java lambda表达式的理解?
  • 优化你的 3D Tiles:性能与质量的平衡
  • 【数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
  • 设计模式之桥接模式:抽象与实现之间的分离艺术
  • 网络隧道与代理
  • 游戏关卡分析:荒野大镖客2雪山终战
  • Java 中的 LocalDateTime、DateTime 和 Date 的区别解析
  • MATLAB引用矩阵元素的几种方法
  • Linux、File System、Linux基本常用命令
  • 大数据治理:开启数据价值挖掘之旅
  • Linux排查cpu运行负载过高
  • Cobalt Strike 4.8 用户指南-第十四节 Aggressor 脚本
  • C++并发与多线程(高级函数async)
  • 安卓课设版算法计算器
  • X-Forwarded-For注入漏洞
  • Linux - MySQL迁移至一主一从
  • 《变形金刚:赛博坦的陨落》游戏启动难题:‘buddha.dll’缺失的七大修复策略