跳到主要内容C++ STL 中 map 与 set 容器的核心用法解析 | 极客日志C++算法
C++ STL 中 map 与 set 容器的核心用法解析
STL 容器 set 基于红黑树实现,支持唯一键值且自动排序,不支持修改 key。multiset 允许重复。map 存储键值对,通过 pair 结构封装。常用操作包括构造、迭代器遍历、insert、erase、find 及 lower_bound/upper_bound 区间查询。C++17 结构化绑定简化了 map 访问。掌握这些特性有助于高效管理数据集合。
一、set/multiset 的使用
set 是存储单一 key 值的容器,其特性如下:
- key 值不支持修改。
- 不允许插入相同的值,若要允许重复需使用 multiset。
- 底层基于红黑树实现。
不支持修改 key 的原因在于底层数据结构。红黑树作为平衡二叉搜索树,严格遵循左子树小于根节点、右子树大于根节点的规则。若随意修改 key,会破坏树的平衡结构,导致查找失效。
1.1 基本结构
set 设计为类模板,方便构造不同类型的集合。
- 第一个模板参数 T:key 的类型。
- 第二个模板参数 Compare:比较逻辑,默认使用缺省值。
- 第三个模板参数 Alloc:内存分配器,一般无需关注。

1.2 构造函数
支持多种初始化方式:空构造、迭代器区间构造、拷贝构造、列表初始化等。
std::set<int> s1;
std::vector<int> v = {3, 4, 2, 6, 5, 7, 8, 10, 9};
std::set<int> s2(v.begin(), v.end());
std::set<int> s3(s2.begin(), s2.end());
std::set<int> s4(s3);
std::set<std::string> s5({"苹果", "香蕉", "梨"});
注意:拷贝构造涉及深拷贝及红黑树重构,性能开销较大。非必要场景尽量使用引用传递以减少负担。
1.3 赋值运算符重载
std::set<std::string> s6 = s5;
std::set<std::string> s7 = {"苹果", "香蕉", "梨"};
1.4 迭代器的使用
set 的迭代器主要用于遍历,不支持修改元素值。遍历时结果为升序序列(中序遍历)。
std::set<std::string> s = {"苹果", "香蕉", "梨", "水蜜桃", "西瓜"};
auto it1 = s.begin();
while (it1 != s.end()) {
std::cout << *it1 << " ";
it1++;
}
1.5 常用方法的使用
(1) empty
std::set<std::string> s1;
std::set<std::string> s2 = {"苹果", "香蕉"};
if (!s1.empty()) std::cout << "set 非空" << std::endl;
else std::cout << "set 为空" << std::endl;
(2) size
std::cout << "s1 的 size:" << s1.size() << std::endl;
std::cout << "s2 的 size:" << s2.size() << std::endl;
(3) insert
插入元素。最常用的是直接插入单个值,返回值包含迭代器和是否插入成功的标志。
std::set<int> s = {3, 2, 5, 6, 4, 9, 7, 8, 1, 10};
for (auto e : s) std::cout << e << " ";
std::cout << std::endl;
s.insert(11);
s.insert(-1);
for (auto e : s) std::cout << e << " ";
(4) erase
删除元素。支持通过迭代器、值或区间删除。返回值为删除的元素个数(用于 multiset 时更有意义)。
std::set<int> s = {3, 2, 5, 6, 4, 9, 7, 8, 1, 10};
if (s.erase(10)) std::cout << "删除成功" << std::endl;
else std::cout << "删除失败,没有这个值" << std::endl;
if (s.erase(100)) std::cout << "删除成功" << std::endl;
else std::cout << "删除失败,没有这个值" << std::endl;
(5) find
查找元素,返回迭代器位置。若未找到则返回 end()。
std::set<int> s = {3, 2, 5, 6, 4, 9, 7, 8, 1, 10};
auto retit1 = s.find(3);
if (retit1 != s.end()) std::cout << "找到了" << std::endl;
else std::cout << "没找到" << std::endl;
(6) count
统计特定值的出现次数。在 set 中通常为 0 或 1。
std::set<int> s = {3, 2, 5, 6, 4, 9, 7, 8, 1, 10};
if (s.count(3)) std::cout << "找到了" << std::endl;
else std::cout << "没找到" << std::endl;
(7) lower_bound / upper_bound
lower_bound(val):返回第一个不小于 val 的迭代器。
upper_bound(val):返回第一个大于 val 的迭代器。
std::set<int> s = {2, 4, 3, 5, 6, 1, 8, 7, 9, 10};
auto retit1 = s.lower_bound(3);
auto retit2 = s.upper_bound(6);
for (auto it1 = retit1; it1 != retit2; it1++) {
std::cout << *it1 << " ";
}
s.erase(retit1, retit2);
二、map 的使用
map 存储键值对(Key-Value),底层同样基于红黑树。相比 set,它需要处理 pair 类型的封装。
2.1 pair 类型
map 元素以 pair 形式存储,包含 first (key) 和 second (value)。
std::pair<std::string, std::string> p2("string", "字符串");
std::cout << "key: " << p2.first << " value: " << p2.second << std::endl;
2.2 基本结构
map 模板参数为 <Key, Value>,其余与 set 类似。
2.3 构造函数
支持空构造、区间构造、拷贝构造及列表初始化。列表初始化在 map 中非常常用。
std::map<int, int> m1;
std::vector<std::pair<int, int>> v = {{1, 100}, {2, 200}};
std::map<int, int> m2(v.begin(), v.end());
std::map<std::string, std::string> m5 = {
{"string", "字符串"},
{"bool", "布尔值"}
};
2.4 访问遍历相关
(1) 迭代器
std::map<std::string, std::string> m = {{"string", "字符串"}};
for (auto it1 = m.begin(); it1 != m.end(); ++it1) {
std::cout << it1->first << ":" << it1->second << std::endl;
}
(2) operator[]
通过下标访问 value。若 key 不存在,会自动创建并默认初始化 value。
m["array"] = "数组";
std::cout << m["string"] << std::endl;
(3) 结构化绑定
for (auto& [k, v] : m) {
std::cout << k << ":" << v << std::endl;
}
2.5 常用方法/重载
(1) insert
插入 pair 数据。若 key 已存在,插入失败,返回的 second 为 false。
std::map<int, int> m = {{1, 100}, {2, 200}};
m.insert({3, 300});
if ((m.insert({1, 999})).second == false) {
std::cout << "插入失败,key 值已存在" << std::endl;
}
(2) operator[]
除了访问,它还兼具插入功能。当 key 不存在且未赋值时,会根据模板类型默认初始化 value。
std::map<std::string, std::string> m = {{"bool", "布尔值"}};
m["bool"] = "xxx";
m["array"] = "数组";
m["string"];
调试结果验证了上述行为,实际开发中可根据需求选择 insert 或 operator[]。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
- HTML转Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
- JSON 压缩
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online