C++ 中 std::set 的用法
std::set 是 C++ STL 中的关联容器,基于红黑树实现,具有以下特点:
- 元素唯一(自动去重)。
- 元素自动有序(默认从小到大排序)。
- 支持快速插入、删除、查找(时间复杂度 O(log N))。
- 常用于需要维护有序唯一元素的场景。
头文件:#include <set>
基本声明:
cpp
#include <set>
#include <iostream>
using namespace std;
set<int> s; // 默认从小到大排序
set<int, greater<int>> s_desc; // 从大到小排序(greater 是比较器)
常见操作
-
插入 :
s.insert(x);(如果已存在则不插入) -
删除 :
s.erase(x);(删除值为 x 的元素)或s.erase(it);(删除迭代器指向的元素) -
查找 :
s.find(x);(返回迭代器,若不存在返回s.end()) -
计数 :
s.count(x);(返回 0 或 1,因为唯一) -
大小 :
s.size(); -
清空 :
s.clear(); -
下界/上界 :
s.lower_bound(x);:返回 >= x 的第一个元素的迭代器s.upper_bound(x);:返回 > x 的第一个元素的迭代器
-
遍历 :
cppfor(auto it = s.begin(); it != s.end(); ++it) { cout << *it << " "; } // 或 C++11 范围 for for(int x : s) { cout << x << " "; }
几个常见例子
-
去重并排序(经典应用:明明的随机数)
cpp#include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; set<int> s; for(int i = 0; i < n; i++) { int x; cin >> x; s.insert(x); // 自动去重并排序 } for(int x : s) cout << x << endl; return 0; } -
维护动态有序集合,求前后继(如营业额统计,求每个数与最近数的差)
cppset<int> s; s.insert(first_value); // 插入第一个 long long ans = 0; for(each new value x) { auto it = s.insert(x).first; // 插入并获取迭代器 if(it != s.begin()) { auto prev = prev(it); // C++11 前驱 ans += *it - *prev; } if(next(it) != s.end()) { ans += *next(it) - *it; } // ... 更新最小等 } -
检查是否存在 + 快速查找
cppset<string> forbidden; forbidden.insert("badword1"); forbidden.insert("badword2"); string word; cin >> word; if(forbidden.count(word)) { cout << "禁止词!" << endl; } -
木材仓库问题(插入/查询/删除相同长度的木材)
cppmultiset<int> ms; // 如果允许重复,用 multiset // 或用 set + map 记录次数
洛谷和力扣(LeetCode)上的经典题目推荐
这些题目都很适合练习 set 的插入、查找、下界等操作。
洛谷(Luogu)经典题目:
- P5250 【深基17.例5】木材仓库 :经典 set/multiset 应用,维护木材长度,查询是否有相同长度。
链接:https://www.luogu.com.cn/problem/P5250 - P2234 [HNOI2002]营业额统计 :用 set 维护已出现数字,lower_bound/upper_bound 求最近差值。
链接:https://www.luogu.com.cn/problem/P2234 - P3370 【模板】字符串哈希 :用 set 存储哈希值去重统计不同字符串数(简单去重)。
链接:https://www.luogu.com.cn/problem/P3370 - NOIP2006 明明的随机数(或类似去重排序题):直接 set 插入遍历输出。
- P5266 【深基17.例6】学籍管理:set 维护学生信息,查询是否存在。
洛谷有专门的"【数据结构1-3】集合"题单,推荐直接刷:https://www.luogu.com.cn/training/158850#problems(包含更多 set 练习题)。
力扣(LeetCode)经典题目:
- 217. Contains Duplicate :用 set 检查是否有重复元素。
链接:https://leetcode.cn/problems/contains-duplicate/ - 414. Third Maximum Number :用 set 维护唯一元素,找第三大。
链接:https://leetcode.cn/problems/third-maximum-number/ - 645. Set Mismatch :找重复和缺失的数字,可用 set。
链接:https://leetcode.cn/problems/set-mismatch/ - 90. Subsets II (子集 II):处理重复元素时用 set 去重(或排序+跳过)。
链接:https://leetcode.cn/problems/subsets-ii/ - 349. Intersection of Two Arrays :用 set 求两个数组交集。
链接:https://leetcode.cn/problems/intersection-of-two-arrays/