set容器
set 是 C++ STL 中实现有序集合的关联式容器 ,底层基于红黑树(平衡二叉搜索树)实现,核心特性是:元素唯一且自动按升序排序,不支持随机访问,插入 / 删除 / 查找操作的时间复杂度均为 O(logn)。 特征:
- 底层实现:红黑树(一种自平衡的二叉搜索树),保证元素有序且操作高效。
- 核心特性 :
- 元素不可重复 (自动去重),若需允许重复元素,使用
multiset; - 元素自动升序排序 (默认按
<比较,也可自定义排序规则); - 不支持直接修改元素(需先删除旧值,再插入新值);
- 支持迭代器遍历,迭代器为双向迭代器(无
[]和at()随机访问)。
- 元素不可重复 (自动去重),若需允许重复元素,使用
基本使用
- 使用
set必须包含头文件
c++
#include <set> // 核心头文件
- 初始化
c++
// 1、默认构造函数,空set(默认升序排列)
set<int> s1;
// 2、初始化列表(c++ 11)
set<int> s2 = { 5, 7, 1, 1, 3, 9 }; // 自动去重 + 升序排列
for (set<int>::iterator it = s2.begin(); it != s2.end(); it++)
{
cout << *it << " "; // 输出1 3 5 7 9
}
cout << endl;
// 3、范围构造,从其他容器/迭代器范围初始化
set<int> s3(++s2.begin(), --s2.end());
for (set<int>::iterator it = s3.begin(); it != s3.end(); it++)
{
cout << *it << " "; // 输出 3 5 7
}
cout << endl;
// 4、自定义排序规则(降序)
set<int, greater<int>> s4 = { 3, 5, 7, 9 };
for (set<int>::iterator it = s4.begin(); it != s4.end(); it++)
{
cout << *it << " "; // 输出 9 7 5 3
}
cout << endl;
// 5、拷贝构造
set<int> s5(s3);
核心操作API
empty()判断 set 是否为空,返回 bool(空为 true)size()返回元素个数(unsigned int 类型)insert(val)插入元素 val,返回pair<iterator, bool>:bool 表示是否插入成功(重复则失败)
! 说明\] `pair
` 是 C++ STL 中 `set`/`map` 等关联式容器的 `insert()`/`emplace()` 函数的**返回值类型**,本质是一个「成对的数据结构」,用来同时返回两个信息:插入操作的结果(是否成功)+ 插入 / 找到的元素的迭代器。 * `first`:存储第一个数据(对应 `set` 插入时的「迭代器」); * `second`:存储第二个数据(对应 `set` 插入时的「是否成功」)。
c++
set<int> s1 = { 5, 7, 1, 1, 3, 9 };
// 插入元素
pair<set<int>::iterator, bool> ret1 = s1.insert(10);
pair<set<int>::iterator, bool> ret2 = s1.insert(1);
for (set<int>::iterator it = s1.begin(); it != s1.end(); it++)
{
cout << *it << " ";
}
cout << endl;
cout << *ret1.first << endl; // 10
cout << ret1.second << endl; // 1
cout << *ret2.first << endl; // 1
cout << ret2.second << endl; // 0
emplace(val)直接构造元素(效率高于 insert),返回值同 inserterase(pos)删除迭代器 pos 指向的元素erase(val)删除值为 val 的元素,返回删除的个数(set 中只能是 0 或 1)
c++
set<int> s1 = { 5, 7, 1, 1, 3, 9 };
int ret = s1.erase(9);
cout << ret << endl; // 1
erase(beg, end)删除 [beg, end) 范围内的元素clear()清空所有元素find(val)查找值为 val 的元素,返回迭代器:找到则指向该元素,否则指向end()count(val)统计值为 val 的元素个数(set 中只能是 0 或 1)lower_bound(val)返回第一个 ≥ val 的元素的迭代器upper_bound(val)返回第一个 > val 的元素的迭代器swap(s)交换两个同类型 set 的内容
进阶用法
- 自定义排序规则
C++
// 自定义降序比较器
struct MyCompare {
bool operator()(int a, int b) const
{
return a > b; // 降序排序
}
};
int main()
{
set<int, MyCompare> s = {5,2,8,1}; // 自定义排序 → {8,5,2,1} cout << "降序遍历:";
for (int num : s)
{
cout << num << " "; // 输出:8 5 2 1 }
return 0;
}
- 存储自定义数据类型(需要重载比较运算符)
! 注意\] 若 `set` 存储自定义结构体 / 类,必须重载 `<` 运算符(或自定义比较器),否则无法排序; 如果需要自定义数据类型按照降序排列,秩序要该return id \> other.id; // 按学号降序
c++
#include <iostream>
#include <set>
#include <string>
using namespace std;
// 自定义结构体:学生(按学号升序排序)
struct Student {
int id;
string name;
// 重载 < 运算符,指定排序规则
bool operator<(const Student& other) const {
return id < other.id; // 按学号升序
}
};
int main() {
set<Student> s;
s.insert({ 2, "Lily" });
s.insert({ 1, "Tom" });
s.insert({ 3, "Jack" });
// 遍历:按学号升序输出
for (const auto& stu : s) {
cout << "学号:" << stu.id << ",姓名:" << stu.name << endl;
}
return 0;
}
- multiset(允许重复元素)
multiset与set用法几乎一致,唯一区别是允许元素重复,核心差异: insert()始终返回迭代器(无 bool 值);count(val)可返回大于 1 的数;erase(val)会删除所有值为 val 的元素。
注意事项
- 元素不可修改 :
set的迭代器是const_iterator(即使写iterator,也无法修改元素),因为修改元素会破坏红黑树的有序性。若需修改,需先删除旧值,再插入新值; - 查找效率 :
find()比count()更高效(find()找到即返回,count()需统计个数),判断元素是否存在优先用find()。 - 迭代器稳定性:插入 / 删除元素时,除被删除元素的迭代器外,其他迭代器仍有效(红黑树特性)。
- 空 set 的 end () :
find()找不到元素时返回end(),不可解引用(*s.end()会崩溃)。
总结语
set是基于红黑树的有序集合,元素唯一且自动升序,操作复杂度 O(logn),无随机访问;- 核心操作:
insert()/emplace()(插入)、erase()(删除)、find()(查找)、clear()(清空),遍历仅支持双向迭代器; - 自定义类型需重载
<运算符,允许重复元素用multiset,修改元素需先删后插。