在 C++ 中,set 是 有序、不重复 的关联容器(底层通常用红黑树实现),核心特性是 自动去重 + 自动排序,非常适合解决 “统计不同元素个数”“快速查找元素” 等场景。
1. 头文件与定义
使用 set 必须包含头文件 <set>,且需指定元素类型(如 int、string 等):
#include <set>
using namespace std; // 简化写法,否则需写 std::set
// 定义一个存储整数的 set(默认升序排序)
set<int> s;
2. 核心操作
| 操作 | 代码示例 | 功能说明 | 时间复杂度 |
|---|---|---|---|
| 插入元素 | s.insert(5); | 插入元素,重复元素会自动忽略 | O(log n) |
| 批量插入(数组) | set<int> s(a, a+n); | 直接用数组区间 [a, a+n) 初始化 set,自动去重 | O(n log n) |
| 获取元素个数 | s.size(); | 返回 set 中不同元素的个数(题目核心需求) | O(1) |
| 清空容器 | s.clear(); | 删除所有元素 | O(n) |
| 判断是否为空 | s.empty(); | 为空返回 true,否则返回 false | O(1) |
| 查找元素 | s.find(3); | 查找元素 3,找到返回迭代器,否则返回 s.end() | O(log n) |
二、结合题目场景的实战用法
之前的题目核心是 “统计数组中不同元素的个数”,用 set 有两种常见实现方式,本质都是利用其 “自动去重” 特性:
方式 1:循环插入(适合动态添加元素)
int get_unique_count(int a[], int n) {
set<int> s;
for (int i = 0; i < n; i++) {
s.insert(a[i]); // 重复元素会被自动过滤
}
return s.size(); // 直接返回不同元素个数
}
方式 2:区间初始化(代码更简洁)
set 支持用迭代器区间直接初始化,数组名本质是指针(可当作迭代器),因此可以一行完成数组元素的去重:
int get_unique_count(int a[], int n) {
set<int> s(a, a + n); // 直接将数组 [a, a+n) 插入 set,自动去重
return s.size();
}
这两种方式结果完全一致,方式 2 更简洁,推荐使用。
三、set 的进阶用法(拓展认知)
1. 遍历 set(查看排序后的元素)
set 是有序的(默认升序),可以通过迭代器遍历所有元素:
set<int> s = {2, 1, 3, 1, 5}; // 初始化时自动去重+排序为 [1,2,3,5]
for (set<int>::iterator it = s.begin(); it != s.end(); it++) {
cout << *it << " "; // 输出:1 2 3 5
}
// C++11 及以上可简化为范围 for 循环
for (int x : s) {
cout << x << " "; // 同样输出:1 2 3 5
}
2. 自定义排序(降序或自定义规则)
默认 set 是升序,若需降序,可在定义时指定排序规则:
// 降序排列的 set
set<int, greater<int>> s = {2, 1, 3, 1, 5};
for (int x : s) {
cout << x << " "; // 输出:5 3 2 1
}
3. 删除元素
set<int> s = {1,2,3,4,5};
s.erase(3); // 删除元素 3(按值删除)
s.erase(s.begin()); // 删除第一个元素(按迭代器删除)
4. 查找元素是否存在
set<int> s = {1,2,3,4,5};
if (s.find(3) != s.end()) {
cout << "元素 3 存在";
} else {
cout << "元素 3 不存在";
}
四、set 的优缺点(对比辅助数组法)
优点:
- 无需关心元素范围:辅助数组法需要假设元素取值范围(如之前的 -1000~1000),
set可处理任意整数(正数、负数、超大数)。 - 代码简洁:无需手动设计去重逻辑,借助容器特性直接实现。
- 支持快速查找:如果后续需要判断某个元素是否存在,
set的查找效率(O (log n))远高于数组遍历(O (n))。
缺点:
- 空间开销略大:底层红黑树需要存储额外的结构(如指针、颜色标记),空间复杂度高于辅助数组(O (n) vs O (1))。
- 排序开销:
set会自动排序,若场景不需要排序,会浪费少量性能(但对于 n≤1000 的题目,完全不影响)。
五、常见误区
- 不能直接修改
set中的元素:set的元素是有序且唯一的,直接修改会破坏其结构,若需修改,需先删除旧元素,再插入新元素。 set的size()是无符号整数:若用int接收(如int len = s.size()),在某些编译器下可能出现类型警告,可通过(int)s.size()强制转换。set不支持随机访问:不能用s[0]访问第一个元素,必须通过迭代器s.begin()或范围 for 循环遍历。
总结
set 是 C++ 中处理 “去重”“统计不同元素”“快速查找” 的利器,核心记住:
- 核心特性:自动去重 + 自动升序排序。
- 题目场景:统计不同元素个数 → 插入
set后返回size()。 - 时间复杂度:插入、查找、删除均为 O (log n),适合 n≤1e5 的场景(远超题目要求的 n≤1000)。
3409

被折叠的 条评论
为什么被折叠?



