掌握C++ set和map:高效关联容器指南

The C++ Standard Library 06 The Standard Template Library 标准模板库 The C++ Standard Library The Standard Template Library (01) STL定义与重要性 The heart of the C++ standard library - the part that influenced its overall architecture - is the standard template library (S 阅读详情

前言:

set 和 map 是处理“集合”和“字典”需求时的首选工具。它们能在 O(log n) 的时间内完成查找、插入和删除,而且容器内的元素始终有序,这是普通数组或链表做不到的。


1. 关联容器概述

C++ 标准库提供了两大类关联容器:

容器特点底层实现
set存放唯一键,按键排序红黑树
multiset存放可重复键,按键排序红黑树
map存放键-值对,键唯一,按键排序红黑树
multimap存放键-值对,键可重复,按键排序红黑树

2. 头文件与基本声明

使用它们之前,需要包含对应的头文件:

#include <set>    // set 和 multiset
#include <map>    // map 和 multimap

声明一个 set 和 map:

std::set<int> s;                        // 存放 int 的集合
std::set<std::string> names;            // 存放字符串的集合

std::map<std::string, int> ages;        // 键为 string,值为 int 的字典
std::map<int, std::string> idToName;    // 键为 int,值为 string

3. set 的基本操作

set 可以理解为自动排序且元素唯一的集合。添加相同元素时,后续的插入会被忽略。

3.1 插入元素

std::set<int> s;
s.insert(30);
s.insert(10);
s.insert(20);
s.insert(10);  // 重复的 10,会被忽略
// 此时 s 内部顺序为:10 20 30

insert 返回一个 pair<iterator, bool>,其中 second 表示插入是否成功:

auto result = s.insert(10);
if (!result.second) {
    std::cout << "10 已经存在,插入失败\n";
}

也可用 emplace 原地构造元素,更高效:

s.emplace(40);  // 直接构造元素

3.2 查找元素

if (s.find(20) != s.end()) {
    std::cout << "找到了 20\n";
}

// 也支持 count,返回 0 或 1
if (s.count(30)) {
    std::cout << "30 存在\n";
}

find 返回迭代器,指向找到的元素;若未找到则返回 end()。

3.3 删除元素

s.erase(20);           // 删除值为 20 的元素
s.erase(s.begin());    // 删除迭代器指向的元素
s.erase(s.begin(), s.find(40)); // 删除一个范围 [first, last)
s.clear();             // 清空

3.4 遍历 set

由于 set 是排序的,遍历时会按照升序输出(默认 std::less)。

for (int x : s) {
    std::cout << x << " ";
}
// 或使用迭代器
for (auto it = s.begin(); it != s.end(); ++it) {
    std::cout << *it << " ";
}

需要注意的是,set 的迭代器是常量双向迭代器,不能通过迭代器修改元素的值(否则会破坏有序性)。


4. map 的基本操作

map 是一个键-值对的集合,每个键都是唯一的。内部也是按键排序的。元素的类型是 std::pair<const Key, T>。

4.1 插入元素

最常用的是使用 insert 或 emplace,或直接用 [] 运算符。

std::map<std::string, int> ages;

// 使用 insert 插入 pair
ages.insert(std::make_pair("Alice", 25));
ages.insert({"Bob", 30});           // C++11 初始化列表

// 使用 emplace 原地构造
ages.emplace("Charlie", 28);

// 使用 [] 操作符(如果键不存在则自动插入,值默认构造)
ages["David"] = 35;  // 插入 "David":35
ages["Alice"] = 26;  // 修改已存在键的值

重要区别:insert 当键已存在时不会覆盖旧值(插入失败),而 [] 总会让键对应的值变成新值(如果不存在就先插入再赋值)。需要根据意图选用。

4.2 访问元素

std::cout << ages["Alice"] << "\n";          // 若不存在会插入,不安全
std::cout << ages.at("Bob") << "\n";         // 若不存在抛 std::out_of_range 异常

// 安全访问:先 find
auto it = ages.find("Charlie");
if (it != ages.end()) {
    std::cout << "Charlie: " << it->second << "\n";
}

遍历 map 时,每个元素是一个 pair,通过 .first 访问键,.second 访问值。

for (const auto& p : ages) {
    std::cout << p.first << " : " << p.second << "\n";
}
// 使用结构化绑定
for (const auto& [name, age] : ages) {
    std::cout << name << " is " << age << " years old.\n";
}

4.3 删除元素

与 set 类似:

ages.erase("Bob");                // 按键删除
auto it = ages.find("Charlie");
if (it != ages.end()) ages.erase(it); // 按迭代器删除

5. 自定义排序规则

set 和 map 默认使用 std::less<Key>,即升序排列。可以通过第二个模板参数指定自定义比较器。

例如,想要一个降序的 set:

std::set<int, std::greater<int>> descSet = {10, 30, 20};
// 遍历输出:30 20 10

对于自定义类型,需要提供比较函数对象或 lambda。

struct Person {
    std::string name;
    int age;
};

// 按年龄升序排列
struct CmpByAge {
    bool operator()(const Person& a, const Person& b) const {
        return a.age < b.age;
    }
};

std::set<Person, CmpByAge> people;
people.insert({"Alice", 30});
people.insert({"Bob", 25});
// 内部顺序:Bob(25) 在 Alice(30) 之前

// 对于 map,比较的是键,所以只需指定键的比较
std::map<Person, int, CmpByAge> personMap;

注意:比较器必须提供一个严格弱序(strict weak ordering),且不可在运行时改变排序规则(它是类型的一部分)。


6. multiset 和 multimap

当需要允许重复键时,就使用 multiset 和 multimap。它们的接口与 set/map 几乎相同,区别在于:

  • insert 永远成功(插入重复键时插入一个新元素)。

  • erase 如果按值删除,会删除所有该值的元素;如果按迭代器,则只删一个。

  • count 可以返回大于 1 的值。

  • find 返回指向第一个匹配元素的迭代器(可以使用 equal_range 获取一个范围)。

示例:

std::multiset<int> ms = {1, 2, 2, 3};
ms.insert(2);                    // 现在有两个 2?
std::cout << ms.count(2) << "\n"; // 输出 3

auto range = ms.equal_range(2);   // pair<iterator, iterator>
for (auto it = range.first; it != range.second; ++it) {
    std::cout << *it << " ";     // 输出所有的 2
}

multimap 类似,但没有 [] 操作符(因为键不唯一,无法确定修改哪个值)。

7. set/map 与 vector/list 的选择

需求推荐容器
需要快速按位置随机访问vector / deque
频繁在头部/中间插入删除,不需要排序list
需要自动去重 + 排序set
需要键值映射 + 按键排序map
仅需判断存在性,且希望 O(log n)set
需要 O(1) 平均查找,不关心顺序unordered_set / unordered_map

一个常见的错误:不要仅仅为了“能快速查找”就直接用 set 或 map。如果数据不需要排序,且对性能要求极高,可以使用无序版本(哈希表)。有序版本的优势在于:可以按顺序遍历、支持范围查询(如 lower_bound/upper_bound)。

8. 有用的成员函数(高级)

set 和 map 还提供了一些实用的二分查找函数:

  • lower_bound(key):返回第一个 不小于 key 的元素的迭代器。

  • upper_bound(key):返回第一个 大于 key 的元素的迭代器。

  • equal_range(key):返回 pair,等价于 make_pair(lower_bound, upper_bound)。

这些在实现区间查询时非常高效,复杂度为 O(log n)

9. 性能提示与注意事项

  1. 内存开销:set 和 map 的每个节点除了存储数据,还要维护三个指针(左孩子、右孩子、父节点)以及颜色信息。相比 vector,它们的内存占用较大且缓存不友好。

  2. 迭代器稳定性:插入和删除元素不会使其他元素的迭代器失效(被删除的那个除外),这点与 list 类似。

  3. 元素不可变:在 set 中存储的元素本身是键,不能修改(因为改了可能破坏排序)。如果确实需要修改,只能先删除再插入。

  4. 避免无意识的插入:使用 [] 访问 map 时,如果键不存在会悄悄插入一个默认值,可能导致意料之外的内存占用。如果只是查找,请使用 find 或 at。

  5. 比较函数必须一致:在 C++ 中,若比较规则不满足严格弱序(如写成 a <= b),行为是未定义的。


10. 小结

  • set 是有序、去重的集合,map 是有序、键唯一的字典。

  • 底层基于红黑树,所有操作 O(log n)。

  • 支持 insert、emplace、find、erase、count、lower_bound 等。

  • 遍历时自动按排序规则输出,默认升序,可自定义比较器。

  • 若需要重复键,使用 multiset / multimap。

  • 若无序但需要平均 O(1) 查找,使用 unordered_set / unordered_map。

  • 多用 find 和 at 而不是盲目用 [],避免意外插入。

c++ 关联容器用法详解(set与map) 三、关联容器 关联容器与序列容器有着根本性的不同,序列容器的元素是按照在容器中的位置来顺序保存和访问的,而关联容器的元素是按关键元素来保存和访问的。关联容器支持高效的关键字查找与访问。两个主要的关联容器类型是map与set。 1.set 1.1 简介:set里面每个元素只存有一个key,它支持高效的关键字查询操作。set对应数学中的“集合”。 1.2 特点: 储存同一类型的数据元素... 阅读详情

相关推荐

C++关联容器

C++关联容器相关知识

Little_pudding10的博客 1220

C++ 关联容器对比详解:map、set、multimap、unordered_map、unordered_set

是否需要顺序:需要顺序遍历或范围查询选有序容器;只需快速查找选无序容器。键是否唯一:唯一键用mapset;允许重复键用multimapmultiset。性能要求:数据量大且哈希质量高时,通常更快;数据量小或需要稳定性能时,有序容器更可靠。内存限制:无序容器可能因预留桶而占用更多内存。在实际开发中,和std::map最为常用,分别代表了哈希表和红黑树两种经典实现。理解它们的底层原理和特性差异,有助于编写出更高效、更清晰的 C++ 代码。

Ash_seven7的博客 333

systemView的安装使用

systemView的安装使用

qq_33712422的博客 3980

Effective STL 第一章 第9条

第9条:慎重选择删除元素的方法 先写总结,在写例子: 1、要删除容器中有特定值的所有对象: 如果容器是vector, string或deque,则使用erase-remove习惯用法 如果容器是list,则使用list::remove 如果容器是一个标准关联容器,则使用它的erase成员函数 2、要删除容器中满足特定判断式(条件)的所有对象: 如果容器是vector、string和d

豆子的collection 852

Apache-Plc4x-Modbus-Tcp学习记录(一)

Apache-Plc4x-Modbus-Tcp学习记录(一)

weixin_45325423的博客 6988

西门子S7-1200/1500 PLC编程与应用技巧

西门子S7-1200 PLC是一款紧凑型的控制器,适用于小型到中型的自动化控制任务。紧凑设计:集成了I/O模块,减少了控制柜的空间需求。高性能:高达25µs的扫描时间,能够快速响应。模块化扩展:支持扩展输入输出模块、通信模块和智能模块,满足不同的应用需求。多种编程语言:支持Ladder图(梯形图)、功能块图(FBD)、结构化文本(ST)等多种编程语言。西门子S7-1200与S7-1500 PLC是强大且灵活的工业控制系统,适用于各种自动化应用。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 2674

【深入C++】map和set的使用

在本篇博客中,我们深入探讨了C++标准库中的map和set容器。通过详细的示例和解释,我们了解了它们的基本用法、常用操作以及在不同场景下的应用。map和set不仅为我们提供了高效的键值对存储和有序集合管理功能,还在复杂数据结构和算法设计中扮演了重要角色。掌握map和set的使用,不仅能够提升我们的编程效率,还能帮助我们编写出更为高效和可靠的代码。在实际开发中,合理地选择和使用这些容器,可以显著优化程序的性能和可维护性。希望通过这篇博客,大家能够对map和set。

2301_79969994的博客 2438

pytorch图像分类篇: 花分类数据集下载和AlexNet网络搭建训练

一、花分类数据集下载 data_setdata_set该文件夹是用来存放训练数据的目录 使用步骤如下: (1)在data_set文件夹下创建新文件夹"flower_data" (2)点击链接下载花分类数据集 (3)解压数据集到flower_data文件夹下 (4)执行"flower_data.py"脚本自动将数据集划分成训练集train和验证集val ├── flower_data ├── flower_photos(解压的数据集文件夹,3670个样本) ...

橙子的博客 8219

C++STL——map和set的使用

set的声明如下,T就是set底层关键字的类型• set默认要求T支持小于比较,如果不支持或者想按自己的需求走可以自行实现仿函数传给第二个模 版参数• set底层存储数据的内存是从空间配置器申请的,如果需要可以自己实现内存池,传给第三个参 数。• ⼀般情况下,我们都不需要传后两个模版参数。• set底层是用红黑树实现,增删查效率是 的。前⾯部分我们已经学习了vector/list等容器的使用,STL容器接口设计,高度相似,在这里我只挑选几个比较重要的接口来将。

2402_86667364的博客 1513

单细胞数据导入实战:Read10X函数常见报错与解决方案

本文针对单细胞转录组分析中Read10X函数数据导入的常见问题,提供了详细的实战解决方案。重点解析了因文件路径错误、压缩文件未解压、版本命名不符及内存不足导致的报错,并给出了检查路径、正确解压、重命名文件、调整参数及优化内存等具体操作步骤,帮助用户高效完成单细胞数据导入,为后续分析奠定坚实基础。

weixin_28235513的博客 239

从安装到跑通第一个例程:Halcon 20.11深度学习版环境搭建全记录

本文详细记录了Halcon 20.11深度学习版环境搭建的全过程,从安装配置到运行第一个例程,特别针对CUDA版本冲突、算子验证和样本数据预处理等常见问题提供解决方案。通过实战案例展示PCB缺陷分类流程,帮助工程师快速掌握工业级图像处理技术,提升深度学习模型在工业质检中的应用效率。

weixin_28739079的博客 221

【C++篇】STL的关联容器:map和set(上篇)—— map和set的介绍和使用

摘要: 本文介绍了C++ STL中的关联容器set和map,两者均基于红黑树实现,具有有序性、唯一性和高效查找的特性。set为单键(K模型),主要用于排序和去重;map为键值对(KV模型),实现映射功能。重点解析了set的count、lower_bound等接口,以及map的插入操作和[]运算符的底层逻辑(通过insert实现访问或插入)。此外,提及了multiset和multimap允许重复键值的场景。最后,建议通过LeetCode题目实践巩固应用。

Surplus886的博客 1092

【错误解决】本地计算机上的mysql服务启动停止后,某些服务在未由其他服务或程序使用时将自动停止

转载请注明出处:http://blog.youkuaiyun.com/qq_26525215 本文源自【大学之旅_谙忆的博客】 在启动mysql服务时出现该错误: 本地计算机上的mysql服务启动停止后,某些服务在未由其他服务或程序使用时将自动停止。mysql 版本 5.7.14 系统 win 7后来经过一系列的百度,谷歌,总算是解决了。首先,你需要把原来的服务删除:mysqld --remove mysq

谙忆-陈浩翔 12万+

C++ STL关联容器:map和set实战

本文介绍了C++ STL中两种重要的关联容器map和set。map存储键值对,自动按键排序且键唯一;set存储唯一元素,自动排序且无键值对概念。文章详细讲解了两种容器的使用方法,包括插入、查找和删除元素的操作示例,并提供了解决键值冲突的方案(如自定义比较规则)。掌握这些容器能有效提升数据存储和查找效率,为后续学习其他STL容器奠定基础。

fykam的博客 875

[PCIE5.0] 2.2.8.9 Optimized Buffer Flush/Fill (OBFF) Message

这段文字讲解的是 优化的缓冲区清空/填充(OBFF)消息,它是 PCI Express(PCIe)规范中的一个可选功能,用于向设备报告平台中央资源的状态。简单来说,OBFF 主要帮助设备了解当前平台资源(如缓存或内存)的状态,从而优化数据的处理和传输。这章重点内容如下。

系统固件工程师 538

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C++关联容器四巨头:map, set, multimap, multiset 深度揭秘

C++标准模板库中的四大关联容器map、set、multimap和multiset都基于红黑树实现,具有有序性和O(logn)操作复杂度的特性。set存储唯一元素集合,map存储唯一键值对,multiset允许重复元素,multimap支持一键多值关系。选择依据主要取决于是否需要存储键值对以及是否允许键重复。这些容器在需要有序数据、快速查找和范围查询的场景中表现出色,开发者应根据具体需求选择最合适的容器类型。

2301_78884150的博客 1014

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

全面解析 C++ STL 中的 set 和 map

基于哈希表实现,提供常数时间复杂度 O(1)O(1)O(1) 的查找和插入操作。是最常用的两类关联容器。希望通过本文的学习,你能够深入掌握这些强大的容器,提升 C++ 编程技能。红黑树的特点确保了查找、插入和删除操作的时间复杂度都为 O(log⁡N)O(\log N)O(logN)。C++ 标准模板库(STL)中的关联式容器以其强大的功能和高效性成为开发者解决复杂数据组织问题的重要工具。在某些场景下非常有用,例如存储学生成绩时,可能有多个学生取得相同的分数。的扩展,允许相同的键有多个值(即支持键的冗余)。

2406_83947720的博客 3748

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

c++关联容器详细介绍

关联容器是C++标准库的一部分,用于存储和管理具有键值对的数据元素。与顺序容器(如vector和list)不同,关联容器的主要特点是它们能够快速查找特定键的值。这是因为关联容器内部使用了高效的数据结构(如二叉树或哈希表)来组织数据。std::set:一个集合,包含唯一元素,按特定顺序排序。std::map:一个映射,包含键值对,其中键是唯一的。std::multiset和std::multimap:类似于set和map,但允许键的重复。

shopeeai的博客 1893

《红黑树驱动的Map/Set实现:C++高效关联容器全解析》

在C++标准库中,map和set作为关联容器的核心,凭借其对数级复杂度的查找效率成为开发利器。然而,理解其底层机制——红黑树的自平衡特性与迭代器设计——才是掌握高阶C++的关键。本文将以零依赖方式实现两套完整容器:基于红黑树的Map<K,V>与Set<T>,涵盖节点结构、插入删除的平衡修复、迭代器失效策略等核心环节,并通过性能对比验证其与STL的等效性。无论您是数据结构学习者还是性能优化实践者,本指南将带您穿透抽象接口,直抵关联容器的设计精髓 

月亮永悬不落,剑指巅峰 784

C++中map和set的详解

在C++编程中,map和set是标准模板库(STL)中两种非常重要的关联容器。它们基于平衡二叉搜索树(通常是红黑树)的数据结构来实现,提供了高效的数据存储和检索功能。本文将详细介绍map和set的特点、用法以及一些常见的操作示例。1. map的基本概念map是一个键值对容器,其中每个键都是唯一的,且按照升序排序。map数据是有序的,方便进行高效的查找、插入和删除操作。查找、插入、删除的平均和最坏时间复杂度都是O(log n),其中n是map中元素的个数。2. map的定义与初始化要使用map。

Hageitow的博客 1191

【C++】关联容器

介绍了关联容器中的map、set、multimap和multiset

dab112的博客 2249

C++关联容器详解:set/map高效操作指南

特性setmultisetmapmultimap存储内容唯一键 (Key可重复键 (Key唯一键值对 (可重复键值对 (元素唯一性键唯一键可重复键唯一键可重复底层结构红黑树 (通常)红黑树 (通常)红黑树 (通常)红黑树 (通常)排序依据Key(按CompareKey(按CompareKey(按CompareKey(按Compare时间复杂度查找、插入、删除: $O(\log n)$查找、插入、删除: $O(\log n)$查找、插入、删除: $O(\log n)$

fegfsf的博客 1239

【c++ primer 笔记】第11章 关联容器

关联容器中的元素按关键字来保存和访问顺序容器中的元素按他们在容器中的位置来保存和访问关联容器与顺序容器许多行为相同,但是有着根本不同,不同之处反应关键字作用关联容器支持高效的关键字查找和访问关联容器包括map和set。头文件定义map和multimap在头文件 map 中,set和multiset在头文件 set 中,无序 map 和无序 set 分别在头文件 unordered_map 和 unordered_set 中。容器类型解释按关键字有序保存元素map关键数组:保存。......

小呆鸟blog 1596

C++关联容器全解析:set/map实战指南

实现,能自动对元素进行排序并支持高效的查找、插入和删除操作。我们将详细解析 C++ 标准库中的。

q_438141的博客 787
上一篇: 掌握二叉搜索树:高效查找的基石
下一篇: AVL树:自平衡二叉搜索树的核心原理
CCCCCCCCharlie
博客等级 码龄1年 2粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值