详细系统讲解 C++ 中的 std::set。我会按照概念→实现原理→常用操作→性能特点→例子→注意事项这种顺序,一步步带你掌握它!
1. 什么是 std::set?
std::set是 C++ STL(标准模板库)里的一个关联容器(Associative Container)。特点:
元素自动排序(默认按从小到大升序排列)。
元素唯一(集合中不能有重复元素)。
本质上,它是用一棵红黑树(Red-Black Tree)实现的。
插入、查找、删除操作的时间复杂度是 O(log n)。
2. 底层原理
红黑树是一种自平衡的二叉搜索树(Binary Search Tree)。
插入或删除节点时,树会自动进行旋转或变色,保持近似平衡。
红黑树保证最长路径不会超过最短路径的2倍,保证了 O(log n) 的操作性能。
所以 std::set 的核心特性有:
元素自动按排序规则排列(默认
operator<)。操作(插入/查找/删除)都在对数时间完成。
3. 头文件和基本定义
#include <set> std::set<int> s; std::set<std::string> mySet;
4. 常用操作总结表
| 操作 | 说明 |
|---|---|
insert(value) | 插入元素,自动排序,重复元素不会插入 |
erase(value) | 删除指定元素 |
find(value) | 查找元素,返回迭代器 |
count(value) | 返回是否存在(存在返回1,不存在返回0) |
size() | 返回元素个数 |
empty() | 是否为空 |
clear() | 清空所有元素 |
begin(), end() | 返回迭代器范围,可用于遍历 |
lower_bound(value) | 返回第一个大于等于 value 的迭代器 |
upper_bound(value) | 返回第一个大于 value 的迭代器 |
emplace(value) | 原地构造元素,效率更高 |
5. 示例代码
基本插入和遍历:
#include <iostream>
#include <set>
int main() {
std::set<int> s;
s.insert(5);
s.insert(2);
s.insert(8);
s.insert(5); // 5已经存在,插入无效
// 遍历:默认升序
for (int x : s) {
std::cout << x << " ";
}
// 输出:2 5 8
}查找和删除元素:
if (s.find(5) != s.end()) {
std::cout << "5 found" << std::endl;
}
s.erase(2); // 删除元素2使用 lower_bound 和 upper_bound:
auto it = s.lower_bound(5); // 找到第一个 >= 5 的元素
if (it != s.end()) {
std::cout << "Lower bound of 5: " << *it << std::endl;
}
auto it2 = s.upper_bound(5); // 找到第一个 > 5 的元素
if (it2 != s.end()) {
std::cout << "Upper bound of 5: " << *it2 << std::endl;
}6. set 和 multiset 的区别
| 特性 | set | multiset |
|---|---|---|
| 元素是否唯一 | 唯一 | 可以有重复 |
| 插入时 | 重复元素被拒绝 | 重复元素可以插入 |
示例:
std::multiset<int> ms; ms.insert(5); ms.insert(5); // 成功插入第二个5
7. std::set 和 std::unordered_set 的区别
| 特性 | set(红黑树) | unordered_set(哈希表) |
|---|---|---|
| 是否有序 | 有序(升序/自定义) | 无序(靠哈希) |
| 查找复杂度 | O(log n) | O(1)平均,O(n)最坏 |
| 内存开销 | 小 | 较大(因为有哈希桶) |
| 插入/查找速度 | 稍慢 | 更快(通常) |
总结一句话:
如果需要有序,用
set;如果只关心快速查找/插入,用unordered_set。
8. 注意事项
默认按
<排序,可以自定义比较函数,比如按降序排列。元素值不可修改!(因为改变值会破坏红黑树结构)。
插入重复元素无效,且不会抛异常。
9. 自定义排序示例(降序)
std::set<int, std::greater<int>> s;
s.insert(5);
s.insert(2);
s.insert(8);
// 输出:8 5 2
for (auto x : s) {
std::cout << x << " ";
}也可以用自定义 struct 作为比较器:
struct Compare {
bool operator()(const int& a, const int& b) const {
return a > b; // 降序
}
};
std::set<int, Compare> s;小结
| 优点 | 缺点 |
|---|---|
| 自动排序、元素唯一、红黑树保证平衡 | O(log n) 比哈希表慢一些,元素值不能直接修改 |
系统当前共有 481 篇文章