一个会自动去重、自动排序的"收纳盒"——放进去的东西不会重复,拿出来的时候总是从小到大的顺序。
set 是一个不重复元素的集合,内部自动排序。你可以把它想象成一个会自动去重、自动排序的"收纳盒"——放进去的东西不会重复,拿出来的时候总是从小到大的顺序。底层和 map 一样是红黑树,只是 set 只存键,不存值。使用前需引入 <set> 头文件。
1 被自动忽略(重复元素不会被插入两次),剩下的元素自动按从小到大排好——这两件事完全不需要手动处理。| 1 | #include <iostream> |
| 2 | #include <set> // 必须包含这个头文件 |
| 3 | using namespace std; |
| 4 | |
| 5 | int 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 那样的 [] 访问方式。| 1 | set<int> s = {3, 1, 4, 1, 5, 9}; // 自动去重并排序:{1, 3, 4, 5, 9} |
| 2 | s.insert(2); // 插入 2:{1, 2, 3, 4, 5, 9} |
| 3 | s.erase(4); // 删除 4:{1, 2, 3, 5, 9} |
| 4 | |
| 5 | // 查找 |
| 6 | if (s.count(3)) { // count 返回 0 或 1 |
| 7 | cout << "3 在集合中" << endl; |
| 8 | } |
| 9 | |
| 10 | auto it = s.find(5); // find 返回迭代器 |
| 11 | if (it != s.end()) { |
| 12 | cout << "找到了: " << *it << endl; |
| 13 | } |
| 14 | |
| 15 | // 遍历(自动从小到大) |
| 16 | for (int x : s) |
| 17 | { |
| 18 | cout << x << " "; // 输出:1 2 3 5 9 |
| 19 | } |
set 没有 first/second(那是 map 的 pair),*it 直接就是存进去的值。同样,set 也不支持 [] 访问——毕竟"键"本身就是"值",用下标访问没有意义。| 对比项 | map | set |
|---|---|---|
| 存储内容 | 键值对(key → value) | 只有键(不重复的值本身) |
| 访问方式 | m[key]、it->first/second | 无 [],*it 直接是元素 |
| 典型用途 | 按键查值 | 去重 + 排序 + 快速判断"是否存在" |
| 无序版本 | unordered_map | unordered_set(用法同理,平均 O(1)) |
| 1 | #include <iostream> |
| 2 | #include <set> |
| 3 | using namespace std; |
| 4 | |
| 5 | int 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 | } |
把本节出现过的方法按用途归类汇总,写代码时可以直接当参考卡用。
| 方法 | 分类 | 作用 |
|---|---|---|
| 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 | 访问 | 解引用迭代器直接拿到元素本身 |
lower_bound 做有序范围查询等。如果只要去重和快速查找、不关心顺序,unordered_set 更快。