c++中的set容器介绍及操作大全
目录
- 一、核心特性
- ️ 二、基本操作
- 1. 初始化与赋值
- 2. 增删查操作
- 3. 遍历方式
- ⚙️ 三、高级操作
- 1. 自定义排序规则
- 2. 范围查询(lower_bound / upper_bound)
- 3. 结构体存储
- ⚖️ 四、性能对比:set vs vector
- 五、典型应用场景
- ⚠️ 六、避坑指南
- 总结
一、核心特性
唯一性与自动排序
std::set存储的元素唯一且默认升序排列(通过std::less实现)。插入重复元素会被自动忽略:
set<int> s = {3, 1, 2, 2}; // 实际存储 {1, 2, 3}
- 底层实现:红黑树(自平衡二叉搜索树),保证插入、删除、查找的时间复杂度为O(log n)
元素不可修改
元素值即键(Key),修改会破坏红黑树结构。迭代器类型为const_iterator,禁止写操作:
auto it = s.find(2); *it = 4; // 编译错误!元素不可直接修改
- 修http://www.devze.com改的正确姿势:先删除旧值,再插入新值
无随机访问
不支持operator[]或下标访问,遍历必须依赖迭代器(双向迭代器,仅支持++/--)
️ 二、基本操作
1. 初始化与赋值
| 方式 | 示例 |
|---|---|
| 默认构造 | set<int> s; |
| 初始化列表 | set<int> s = {1, 3, 2}; → {1, 2, 3} |
| 迭代器范围初始化 | vector<int> v{5,4,3}; s编程et<int> s(v.begin(), v.end()); |
| 自定义排序规则 | set<int, greater<int>> s;(降序)4 12 |
2. 增删查操作
| 操作 | 函数 | 示例 | 返回值 |
|---|---|---|---|
| 插入元素 | insert(value) | s.insert(4); | pair<iter, bool>(成功时bool=true) |
| 删除元素 | erase(key) / erase(iter) | s.erase(3); 或 s.erase(s.begin()); | 返回被删元素后的迭代器 |
| 查找元素 | find(key) | auto it = s.find(2); | 找到返回迭代器,否则返回s.end() |
| 统计元素存在性 | count(key) | if (s.count(2)) { ... } | 0或1(因元素唯一)1 9 |
3. 遍历方式
// 迭代器遍历
for (auto it = s.begin(); it != s.end(); ++it) {
cout << *it << " ";
}
// 范围循环(C++11)
for (int val : s) {
cout << val << " ";
}
⚙️ 三、高级操作
1. 自定义排序规则
通过函数对象或Lambda实现复杂排序:
struct CaseInsensitiveCompare {
bool operator()(const string& a, const string& b) const {
return tolower(a[0]) < tolower(b[0]); // 首字母不区分大小写
}
};
set<string, CaseInsensitiveCompare> s;
2. 范围查询(lower_bound / upper_bound)
set<int> s = {10, 20, 30, 40};
auto low = s.lower_bound(20); // 首个 ≥20 的元素 → 20
auto high = s.upper_bound(30); // 首个 >30 的元素 → 40
- 应用场景:快速定位有序数据中的区间
3. 结构体存储
需重载operator<:
struct Person {
string name;
int age;
bool operator<(const Person& p) const {
return age < p.age; // 按年龄升序
}
};
set<Person> s = {{"Alice", 30}, {"Bob", 25}};
⚖️ 四、性能对比:set vs vector
| 操作 | set | vector | 适用场景 |
|---|---|---|---|
| 插入/删除 | O(log n)(任意位置) | O(n)(非尾部操作) | 频繁中间插入/删除 → 选set |
| 查找 | O(log n)(二分查找) | O(n)(线性遍历) | 高频查找 → 选set |
| 随机访问 | ❌ 不支持 | ✅ O(1) | 按索引访问 → 选vector |
| 内存占用 | 较高(树节点开销) | 较低(连续内存) | 内存敏感 → 选vector |
| 元素顺序 | 自动排序 | 插入顺序 | 需有序 → 选set |
关键结论:
- 唯一性+有序性需求优先选
set - 随机访问+连续存储需求优先选
vector
五、典型应用场景
数据去重与排序
从重复数据中提取唯一有序序列:vector<int> data = {5, 3, 5, 2, 1};
set<int> unique_sorted(data.begin(), data.end()); // {1, 2, 3, 5}
高效存在性检查
黑名单/白名单快速过滤:set<string> blacklist = {"user1", "user2"};
if (blacklist.find(input_user) != blacklist.end()) block_user();
范围统计与区间查询
成绩分级、区间数据分析:set<int> scores = {60, 75, 85, 90};
auto pass = scores.lower_bound(60); // ≥60的第一个元素
⚠️ 六、避坑指南
- 迭代器失效问题
删除元素时,仅被删元素的迭代器失效,其他迭代器仍有效。
- 无android法修改元素值
“修改”需先删除再插入:
auto it = s.find(old_val);
if (it != s.end()) 编程{
s.erase(it);
s.insert(new_val); // 安全修改
}
- 自定义类型必须重载
operator< - 否则编译失败(红黑树需比较规则)。
总结
- 核心优势:自动去重、有序存储、O(log n)高效操作;
- 核心局编程客栈限:无随机访问、内存开销较高;
- 替代方案:
- 需重复元素 →
multiset; - 需O(1)查找 →
unordered_set(哈希表实现,无序)。
- 需重复元素 →
到此这篇关于c++中的set容器介绍及操作大全的文章就介绍到这了,更多相关c++ set容器内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
加载中,请稍侯......
精彩评论