首页 / 第十一章 · STL 标准模板库 / 11.10 set

11.10 set 有序集合

一个会自动去重、自动排序的"收纳盒"——放进去的东西不会重复,拿出来的时候总是从小到大的顺序。

本页目录

set 是一个不重复元素的集合,内部自动排序。你可以把它想象成一个会自动去重、自动排序的"收纳盒"——放进去的东西不会重复,拿出来的时候总是从小到大的顺序。底层和 map 一样是红黑树,只是 set 只存键,不存值。使用前需引入 <set> 头文件。

放进 set:自动去重 + 自动排序
插入顺序:
3
1
4
1
5
9
set 内部实际存储:
1
3
4
5
9
第二个 1 被自动忽略(重复元素不会被插入两次),剩下的元素自动按从小到大排好——这两件事完全不需要手动处理。
11.10.1 定义与初始化
C++ · set 的定义方式
1#include <iostream>
2#include <set> // 必须包含这个头文件
3using namespace std;
4
5int main()
6{
7 set<int> s1; // 空集合
8 set<int> s2 = {3, 1, 4, 1, 5}; // 自动去重排序:{1, 3, 4, 5}
9 set<int> s3(s2); // 拷贝构造
10 return 0;
11}
⚠️
注意:
· set 中的元素本身既是"键",也相当于一个不能修改的"值"——没有 map 那样的 [] 访问方式。
· 元素一旦插入,不能直接修改,只能先删除再插入新值。
· 底层为红黑树,插入、删除、查找都是 O(log n)。
11.10.2 常用操作
C++ · insert / erase / find / count
1set<int> s = {3, 1, 4, 1, 5, 9}; // 自动去重并排序:{1, 3, 4, 5, 9}
2s.insert(2); // 插入 2:{1, 2, 3, 4, 5, 9}
3s.erase(4); // 删除 4:{1, 2, 3, 5, 9}
4
5// 查找
6if (s.count(3)) { // count 返回 0 或 1
7 cout << "3 在集合中" << endl;
8}
9
10auto it = s.find(5); // find 返回迭代器
11if (it != s.end()) {
12 cout << "找到了: " << *it << endl;
13}
14
15// 遍历(自动从小到大)
16for (int x : s)
17{
18 cout << x << " "; // 输出:1 2 3 5 9
19}
💡
解引用迭代器拿到的是元素本身:set 没有 first/second(那是 mappair),*it 直接就是存进去的值。同样,set 也不支持 [] 访问——毕竟"键"本身就是"值",用下标访问没有意义。
对比项mapset
存储内容键值对(key → value)只有键(不重复的值本身)
访问方式m[key]、it->first/second无 [],*it 直接是元素
典型用途按键查值去重 + 排序 + 快速判断"是否存在"
无序版本unordered_mapunordered_set(用法同理,平均 O(1))
11.10.3 完整使用示例
C++ · set 综合示例
1#include <iostream>
2#include <set>
3using namespace std;
4
5int main()
6{
7 set<int> s = {3, 1, 4, 1, 5, 9}; // 自动去重并排序:{1, 3, 4, 5, 9}
8 s.insert(2); // 插入 2:{1, 2, 3, 4, 5, 9}
9 s.erase(4); // 删除 4:{1, 2, 3, 5, 9}
10
11 // 查找
12 if (s.count(3))
13 {
14 cout << "3 在集合中" << endl;
15 }
16
17 auto it = s.find(5);
18 if (it != s.end())
19 {
20 cout << "找到了: " << *it << endl;
21 }
22
23 // 遍历(自动从小到大)
24 cout << "遍历: ";
25 for (int x : s)
26 {
27 cout << x << " "; // 输出:1 2 3 5 9
28 }
29 cout << endl;
30
31 return 0;
32}
📋 set 常用操作速查表

把本节出现过的方法按用途归类汇总,写代码时可以直接当参考卡用。

方法分类作用
s.insert(x)插入插入元素,已存在则忽略,O(log n)
s.erase(x)删除删除指定元素
s.find(x)查找返回迭代器,没找到返回 end()
s.count(x)查找判断元素是否存在,返回 0 或 1
s.size() / s.empty()容量元素个数 / 判断是否为空
s.clear()容量清空所有元素
s.begin() / s.end()遍历正向迭代器范围,自动从小到大
*it访问解引用迭代器直接拿到元素本身
🎯
什么时候用 set?需要去重、需要保持有序、需要频繁判断"某个元素是否出现过"的场景:去重统计不同元素个数、维护一个动态变化的有序数列、配合 lower_bound 做有序范围查询等。如果只要去重和快速查找、不关心顺序,unordered_set 更快。