第一章 函数列表与讲解
1.1 构造与初始化
默认构造
- 函数功能:创建一个空的 std::set 容器。
- 函数入参:无
- 函数返回值:返回一个空的 std::set 对象
- 使用举例:
std::set<int> s;
区间构造
- 函数功能:通过迭代器区间 [first, last) 构造集合,自动去重并排序。
- 函数入参:
- first:输入迭代器,指向范围起始位置
- last:输入迭代器,指向范围结束位置(不包含)
- 函数返回值:返回包含区间内所有唯一元素的 std::set 对象
- 使用举例:
std::vector<int> vec = {4, 2, 7, 1, 9, 2, 4};
std::set<int> s(vec.begin(), vec.end());
初始化列表构造
- 函数功能:通过初始化列表构造集合,自动去重并排序。
- 函数入参:
- init:std::initializer_list<T> 类型的初始化列表
- 函数返回值:返回包含列表中所有唯一元素的 std::set 对象
- 使用举例:
std::set<int> s = {5, 3, 8, 1, 9, 3, 5};
拷贝构造
- 函数功能:从另一个同类型集合复制所有元素构造新集合。
- 函数入参:
- other:被拷贝的 const std::set& 对象
- 函数返回值:返回与源集合内容完全相同的新 std::set 对象
- 使用举例:
std::set<int> src = {1, 2, 3};
std::set<int> s(src);
移动构造
- 函数功能:通过移动语义将源集合的资源转移到新集合,源集合变为有效但未指定状态。
- 函数入参:
- other:std::set&& 右值引用
- 函数返回值:返回接管了源集合资源的新 std::set 对象
- 使用举例:
std::set<int> s(std::move(src));
自定义比较器构造
- 函数功能:使用自定义比较器类型构造集合,元素按自定义规则排序。
- 函数入参:
- 模板参数 Compare:自定义比较器类型(需重载 operator())
- 可选的初始化列表或迭代器区间
- 函数返回值:返回按自定义比较规则排序的 std::set 对象
- 使用举例:
struct DescendingCompare {
bool operator()(int a, int b) const { return a > b; }
};
std::set<int, DescendingCompare> s = {3, 1, 4, 1, 5};
1.2 插入操作
insert(单元素)
- 函数功能:向集合中插入一个元素。若元素已存在则不插入。
- 函数入参:
- value:要插入的元素值(const T& 或 T&&)
- 函数返回值:std::pair<iterator, bool>,first 为指向插入位置(或已存在元素)的迭代器,second 为是否插入成功
- 使用举例:
auto result = s.insert(4);
if (result.second) { /* 插入成功 */ }
insert(提示位置)
- 函数功能:在给定提示位置附近插入元素,若提示位置正确可优化插入性能。
- 函数入参:
- hint:迭代器,建议的插入位置
- value:要插入的元素值
- 函数返回值:指向插入元素(或已存在元素)的迭代器
- 使用举例:
auto it = s.insert(s.begin(), 6);
insert(区间)
- 函数功能:将迭代器区间 [first, last) 内的所有元素插入集合。
- 函数入参:
- first:输入迭代器,范围起始
- last:输入迭代器,范围结束(不包含)
- 函数返回值:无(void)
- 使用举例:
std::vector<int> vec = {11, 13, 15};
s.insert(vec.begin(), vec.end());
insert(初始化列表)
- 函数功能:将初始化列表中的所有元素插入集合。
- 函数入参:
- init:std::initializer_list<T> 类型
- 函数返回值:无(void)
- 使用举例:
s.insert({10, 20, 30, 40, 50});
emplace
- 函数功能:原地构造元素并插入集合,避免临时对象的创建和拷贝。
- 函数入参:
- args…:传递给元素构造函数的参数包
- 函数返回值:std::pair<iterator, bool>,含义同 insert
- 使用举例:
auto result = s.emplace("Alice", 20, 95.5);
emplace_hint
- 函数功能:在提示位置附近原地构造元素并插入,兼具提示优化和原地构造优势。
- 函数入参:
- hint:迭代器,建议的插入位置
- args…:传递给元素构造函数的参数包
- 函数返回值:指向插入元素的迭代器
- 使用举例:
auto it = s.emplace_hint(s.upper_bound(25), 25);
1.3 删除操作
erase(按值)
- 函数功能:删除集合中等于指定值的元素。
- 函数入参:
- key:要删除的元素值
- 函数返回值:size_type,被删除的元素个数(0 或 1)
- 使用举例:
size_t count = s.erase(5);
erase(按迭代器)
- 函数功能:删除迭代器指向的单个元素。
- 函数入参:
- pos:指向要删除元素的迭代器
- 函数返回值:指向被删除元素之后元素的迭代器(C++11 起)
- 使用举例:
auto it = s.find(3);
if (it != s.end()) s.erase(it);
erase(按区间)
- 函数功能:删除迭代器区间 [first, last) 内的所有元素。
- 函数入参:
- first:起始迭代器
- last:结束迭代器(不包含)
- 函数返回值:指向被删除区间之后元素的迭代器
- 使用举例:
s.erase(s.lower_bound(6), s.upper_bound(8));
clear
- 函数功能:删除集合中所有元素,使集合变为空。
- 函数入参:无
- 函数返回值:无(void)
- 使用举例:
s.clear();
1.4 查找操作
find
- 函数功能:查找集合中等于指定值的元素。
- 函数入参:
- key:要查找的值
- 函数返回值:若找到返回指向该元素的迭代器,否则返回 end()
- 使用举例:
auto it = s.find(50);
if (it != s.end()) { /* 找到 */ }
count
- 函数功能:统计集合中等于指定值的元素个数。对于 set 只可能返回 0 或 1。
- 函数入参:
- key:要统计的值
- 函数返回值:size_type,匹配元素的个数
- 使用举例:
size_t cnt = s.count(30);
lower_bound
- 函数功能:返回指向第一个不小于(≥)给定值的元素的迭代器。
- 函数入参:
- key:比较的下限值
- 函数返回值:指向第一个 ≥ key 的元素的迭代器,若不存在则返回 end()
- 使用举例:
auto it = s.lower_bound(45);
upper_bound
- 函数功能:返回指向第一个大于(>)给定值的元素的迭代器。
- 函数入参:
- key:比较的上限值
- 函数返回值:指向第一个 > key 的元素的迭代器,若不存在则返回 end()
- 使用举例:
auto it = s.upper_bound(50);
equal_range
- 函数功能:返回等于给定值的元素范围,等价于 {lower_bound(key), upper_bound(key)}。
- 函数入参:
- key:要查找的值
- 函数返回值:std::pair<iterator, iterator>,first 为下界,second 为上界
- 使用举例:
auto range = s.equal_range(60);
for (auto it = range.first; it != range.second; ++it) { /* … */ }
contains(C++20)
- 函数功能:判断集合中是否包含等于指定值的元素。
- 函数入参:
- key:要判断的值
- 函数返回值:bool,包含返回 true,否则返回 false
- 使用举例:
bool exists = s.contains(70);
1.5 遍历操作
begin / end
- 函数功能:返回指向集合首元素和尾后位置的正向迭代器。
- 函数入参:无
- 函数返回值:
- begin():指向第一个元素的迭代器
- end():指向最后一个元素之后位置的迭代器
- 使用举例:
for (auto it = s.begin(); it != s.end(); ++it) { std::cout << *it; }
rbegin / rend
- 函数功能:返回指向集合尾元素和首前位置的反向迭代器,用于逆序遍历。
- 函数入参:无
- 函数返回值:
- rbegin():指向最后一个元素的反向迭代器
- rend():指向第一个元素之前位置的反向迭代器
- 使用举例:
for (auto it = s.rbegin(); it != s.rend(); ++it) { std::cout << *it; }
cbbegin / cend
- 函数功能:返回常量正向迭代器,保证不能通过迭代器修改元素。
- 函数入参:无
- 函数返回值:
- cbegin():const_iterator,指向第一个元素
- cend():const_iterator,指向尾后位置
- 使用举例:
for (auto it = s.cbegin(); it != s.cend(); ++it) { std::cout << *it; }
crbegin / crend
- 函数功能:返回常量反向迭代器,用于不可修改的逆序遍历。
- 函数入参:无
- 函数返回值:
- crbegin():const_reverse_iterator,指向最后一个元素
- crend():const_reverse_iterator,指向首前位置
- 使用举例:
for (auto it = s.crbegin(); it != s.crend(); ++it) { std::cout << *it; }
1.6 容量操作
size
- 函数功能:返回集合中当前元素的个数。
- 函数入参:无
- 函数返回值:size_type,元素个数
- 使用举例:
std::cout << s.size();
empty
- 函数功能:判断集合是否为空。
- 函数入参:无
- 函数返回值:bool,为空返回 true,否则返回 false
- 使用举例:
if (s.empty()) { /* 集合为空 */ }
max_size
- 函数功能:返回集合理论上能容纳的最大元素数量。
- 函数入参:无
- 函数返回值:size_type,最大可容纳元素数
- 使用举例:
std::cout << s.max_size();
1.7 交换操作
swap
- 函数功能:交换两个集合的所有内容,时间复杂度为 O(1)。
- 函数入参:
- other:要交换的另一个同类型 std::set&
- 函数返回值:无(void)
- 使用举例:
s1.swap(s2);
1.8 比较操作
operator== / != / < / <= / > / >=
- 函数功能:按字典序比较两个集合的内容。
- 函数入参:
- lhs:左操作数 const std::set&
- rhs:右操作数 const std::set&
- 函数返回值:bool,比较结果
- 使用举例:
bool eq = (s1 == s2);
bool lt = (s1 < s2);
1.9 合并与提取(C++17)
merge
- 函数功能:将源集合中不与目标集合重复的元素转移到目标集合,源集合中重复元素保留。
- 函数入参:
- source:同类型的 std::set&,元素来源
- 函数返回值:无(void)
- 使用举例:
dest.merge(src);
extract(按值)
- 函数功能:从集合中提取指定值的节点,不销毁元素,可修改后重新插入。
- 函数入参:
- key:要提取的元素值
- 函数返回值:node_type,若找到则持有该元素,否则为空节点
- 使用举例:
auto nh = s.extract(30);
if (!nh.empty()) { std::cout << nh.value(); }
extract(按迭代器)
- 函数功能:提取迭代器指向位置的节点。
- 函数入参:
- pos:指向要提取元素的迭代器
- 函数返回值:node_type,持有被提取的元素
- 使用举例:
auto nh = s.extract(s.find(20));
insert(节点)
- 函数功能:将之前提取的节点重新插入集合。
- 函数入参:
- nh:node_type&&,右值引用的节点句柄
- 函数返回值:insert_return_type,包含迭代器和是否插入成功标志
- 使用举例:
nh.value() = 120;
s.insert(std::move(nh));
1.10 获取比较器
key_comp
- 函数功能:返回用于比较键的比较器对象副本。
- 函数入参:无
- 函数返回值:key_compare 类型的比较器对象
- 使用举例:
auto comp = s.key_comp();
bool result = comp(5, 3);
value_comp
- 函数功能:返回用于比较值的比较器对象副本。对于 set,与 key_comp() 等价。
- 函数入参:无
- 函数返回值:value_compare 类型的比较器对象
- 使用举例:
auto vcomp = s.value_comp();
bool result = vcomp(5, 3);
第二章 分模块代码
2.1 自定义类型定义
使用说明:定义 Student 类作为自定义元素类型,通过重载 operator< 实现按分数升序、同分按姓名排序的规则;定义 DescendingCompare 仿函数实现整数降序排列。这两个类型为后续所有模块提供基础支撑。
#include<iostream>
#include<set>
#include<string>
#include<vector>
#include<algorithm>
#include<functional>
class Student
{
private:
std::string name_;
int age_ = 0;
double score_ = 0.0;
public:
Student() : name_(""), age_(0), score_(0.0) { }
Student(const std::string& name, int age, double score)
: name_(name), age_(age), score_(score) { }
bool operator<(const Student& other) const
{
if (score_ != other.score_)
return score_ < other.score_;
return name_ < other.name_;
}
bool operator==(const Student& other) const
{
return name_ == other.name_ &&
age_ == other.age_ &&
score_ == other.score_;
}
friend std::ostream& operator<<(std::ostream& os, const Student& s)
{
os << "Student{name=" << s.name_ << ", age=" << s.age_ << ", score=" << s.score_ << "}";
return os;
}
std::string getName() const { return name_; }
int getAge() const { return age_; }
double getScore() const { return score_; }
};
class DescendingCompare
{
public:
bool operator()(int a, int b) const
{
return a > b;
}
};
2.2 构造与初始化
使用说明:演示 std::set 的六种构造方式。默认构造创建空集合;区间构造和初始化列表构造自动去重排序;拷贝构造深拷贝;移动构造转移资源避免拷贝开销;自定义比较器构造可改变默认排序方向。
std::set<int> constructDefault()
{
std::set<int> s;
return s;
}
std::set<int> constructWithRange(const std::vector<int>& vec)
{
std::set<int> s(vec.begin(), vec.end());
return s;
}
std::set<int> constructWithInitializerList()
{
std::set<int> s = { 5, 3, 8, 1, 9, 3, 5 };
return s;
}
std::set<int> constructCopy(const std::set<int>& src)
{
std::set<int> s(src);
return s;
}
std::set<int> constructMove(std::set<int>&& src)
{
std::set<int> s(std::move(src));
return s;
}
std::set<int, DescendingCompare> constructWithCustomComparator()
{
std::set<int, DescendingCompare> s = { 3, 1, 4, 1, 5, 9, 2, 6 };
return s;
}
std::set<Student> constructWithClassType()
{
std::set<Student> s;
s.insert(Student("Alice", 20, 95.5));
s.insert(Student("Bob", 21, 88.0));
s.insert(Student("Charlie", 19, 92.3));
s.insert(Student("Alice", 22, 85.0));
return s;
}
void demoConstruction()
{
std::cout << "===== 构造与初始化 =====" << std::endl;
auto s1 = constructDefault();
std::cout << "默认构造,size = " << s1.size() << std::endl;
auto s2 = constructWithRange({ 4, 2, 7, 1, 9, 2, 4 });
std::cout << "区间构造: ";
for (const auto& v : s2) std::cout << v << " ";
std::cout << std::endl;
auto s3 = constructWithInitializerList();
std::cout << "初始化列表构造: ";
for (const auto& v : s3) std::cout << v << " ";
std::cout << std::endl;
auto s4 = constructCopy(s3);
std::cout << "拷贝构造: ";
for (const auto& v : s4) std::cout << v << " ";
std::cout << std::endl;
auto s5 = constructMove(std::set<int>{100, 200, 300});
std::cout << "移动构造: ";
for (const auto& v : s5) std::cout << v << " ";
std::cout << std::endl;
auto s6 = constructWithCustomComparator();
std::cout << "自定义比较器(降序)构造: ";
for (const auto& v : s6) std::cout << v << " ";
std::cout << std::endl;
auto s7 = constructWithClassType();
std::cout << "自定义类类型构造:" << std::endl;
for (const auto& stu : s7) std::cout << " " << stu << std::endl;
}
2.3 插入操作
使用说明:演示 insert 的四种重载形式及 emplace 系列。单元素插入通过返回值的 second 判断是否成功;提示插入在已知大致位置时可优化为 O(1);区间插入和初始化列表插入适合批量添加;emplace 直接原地构造避免临时对象,对复杂类型性能更优。
void insertSingle(std::set<int>& s, int value)
{
auto result = s.insert(value);
if (result.second)
{
std::cout << "插入成功: " << value << std::endl;
}
else
{
std::cout << "插入失败(已存在): " << value << std::endl;
}
}
void insertWithHint(std::set<int>& s, int value)
{
auto hint = s.begin();
auto it = s.insert(hint, value);
std::cout << "提示插入: " << *it << std::endl;
}
void insertRange(std::set<int>& s, const std::vector<int>& vec)
{
s.insert(vec.begin(), vec.end());
std::cout << "区间插入完成,当前大小: " << s.size() << std::endl;
}
void insertInitializerList(std::set<int>& s)
{
s.insert({ 10, 20, 30, 40, 50 });
std::cout << "初始化列表插入完成,当前大小: " << s.size() << std::endl;
}
void emplaceElement(std::set<Student>& s, const std::string& name, int age, double score)
{
auto result = s.emplace(name, age, score);
if (result.second)
{
std::cout << "emplace成功: " << *result.first << std::endl;
}
else
{
std::cout << "emplace失败(已存在): " << *result.first << std::endl;
}
}
void emplaceHintElement(std::set<int>& s, int value)
{
auto hint = s.upper_bound(value);
auto it = s.emplace_hint(hint, value);
std::cout << "emplace_hint插入: " << *it << std::endl;
}
void demoInsert()
{
std::cout << "\\n===== 插入操作 =====" << std::endl;
std::set<int> insertSet = { 1, 3, 5, 7, 9 };
std::cout << "初始集合: ";
for (const auto& v : insertSet) std::cout << v << " ";
std::cout << std::endl;
insertSingle(insertSet, 4);
insertSingle(insertSet, 5);
insertWithHint(insertSet, 6);
insertRange(insertSet, { 11, 13, 15 });
insertInitializerList(insertSet);
std::cout << "最终集合: ";
for (const auto& v : insertSet) std::cout << v << " ";
std::cout << std::endl;
std::cout << "\\n— emplace演示 —" << std::endl;
std::set<Student> studentSet;
emplaceElement(studentSet, "David", 23, 91.0);
emplaceElement(studentSet, "David", 23, 91.0);
std::cout << "\\n— emplace_hint演示 —" << std::endl;
std::set<int> emplaceSet = { 10, 20, 30 };
emplaceHintElement(emplaceSet, 25);
std::cout << "emplace_hint后集合: ";
for (const auto& v : emplaceSet) std::cout << v << " ";
std::cout << std::endl;
}
2.4 删除操作
使用说明:演示三种粒度的删除方式。按值删除返回删除个数(0或1),适合不确定元素是否存在时;按迭代器删除需先通过 find 定位,适合已知元素位置时;按区间删除配合 lower_bound/upper_bound 可批量移除一段范围内的元素;clear 一次性清空全部。
bool eraseByValue(std::set<int>& s, int value)
{
size_t count = s.erase(value);
return count > 0;
}
void eraseByIterator(std::set<int>& s, int value)
{
auto it = s.find(value);
if (it != s.end())
{
s.erase(it);
std::cout << "通过迭代器删除: " << value << std::endl;
}
}
void eraseByRange(std::set<int>& s, int low, int high)
{
auto itLow = s.lower_bound(low);
auto itHigh = s.upper_bound(high);
s.erase(itLow, itHigh);
std::cout << "区间删除 [" << low << ", " << high << "] 完成" << std::endl;
}
void clearAll(std::set<int>& s)
{
s.clear();
std::cout << "清空完成,当前大小: " << s.size() << std::endl;
}
void demoErase()
{
std::cout << "\\n===== 删除操作 =====" << std::endl;
std::set<int> eraseSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::cout << "初始集合: ";
for (const auto& v : eraseSet) std::cout << v << " ";
std::cout << std::endl;
bool r1 = eraseByValue(eraseSet, 5);
std::cout << "eraseByValue(5) 结果: " << (r1 ? "true" : "false") << std::endl;
bool r2 = eraseByValue(eraseSet, 99);
std::cout << "eraseByValue(99) 结果: " << (r2 ? "true" : "false") << std::endl;
eraseByIterator(eraseSet, 3);
eraseByRange(eraseSet, 6, 8);
traverseForward(eraseSet);
clearAll(eraseSet);
}
2.5 查找操作
使用说明:演示 set 的全部查找接口。find 返回迭代器用于后续操作;count 对 set 仅返回 0/1,语义上等价于存在性判断;lower_bound/upper_bound 用于定位范围边界,是区间操作的基础;equal_range 一次获取上下界;contains(C++20)是最简洁的存在性判断方式。
bool findByValue(const std::set<int>& s, int value)
{
auto it = s.find(value);
if (it != s.end())
{
std::cout << "找到: " << *it << std::endl;
return true;
}
std::cout << "未找到: " << value << std::endl;
return false;
}
size_t countValue(const std::set<int>& s, int value)
{
size_t cnt = s.count(value);
std::cout << "值 " << value << " 出现次数: " << cnt << std::endl;
return cnt;
}
void lowerBoundDemo(const std::set<int>& s, int value)
{
auto it = s.lower_bound(value);
if (it != s.end())
{
std::cout << "lower_bound(" << value << ") = " << *it << std::endl;
}
else
{
std::cout << "lower_bound(" << value << ") = end()" << std::endl;
}
}
void upperBoundDemo(const std::set<int>& s, int value)
{
auto it = s.upper_bound(value);
if (it != s.end())
{
std::cout << "upper_bound(" << value << ") = " << *it << std::endl;
}
else
{
std::cout << "upper_bound(" << value << ") = end()" << std::endl;
}
}
void equalRangeDemo(const std::set<int>& s, int value)
{
auto range = s.equal_range(value);
std::cout << "equal_range(" << value << "): [";
for (auto it = range.first; it != range.second; it++)
{
std::cout << *it << " ";
}
std::cout << "]" << std::endl;
}
bool containsValue(const std::set<int>& s, int value)
{
#if _MSVC_LANG >= 202002L
bool result = s.contains(value);
std::cout << "contains(" << value << ") = " << (result ? "true" : "false") << std::endl;
return result;
#else
std::cout << "需要支持C++20" << std::endl;
return false;
#endif
}
void demoFind()
{
std::cout << "\\n===== 查找操作 =====" << std::endl;
std::set<int> findSet = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
std::cout << "集合: ";
for (const auto& v : findSet) std::cout << v << " ";
std::cout << std::endl;
findByValue(findSet, 50);
findByValue(findSet, 55);
countValue(findSet, 30);
countValue(findSet, 35);
lowerBoundDemo(findSet, 45);
lowerBoundDemo(findSet, 50);
upperBoundDemo(findSet, 50);
upperBoundDemo(findSet, 100);
equalRangeDemo(findSet, 60);
containsValue(findSet, 70);
containsValue(findSet, 75);
}
2.6 遍历操作
使用说明:演示五种遍历方式。正向迭代器 begin/end 按升序访问;反向迭代器 rbegin/rend 按降序访问;范围 for 循环语法最简洁;cbegin/cend 和 crbegin/crend 返回常量迭代器,确保遍历过程中不会意外修改元素,适合只读场景。
void traverseForward(const std::set<int>& s)
{
std::cout << "正向遍历: ";
for (auto it = s.begin(); it != s.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
void traverseBackward(const std::set<int>& s)
{
std::cout << "反向遍历: ";
for (auto it = s.rbegin(); it != s.rend(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
void traverseRangeFor(const std::set<int>& s)
{
std::cout << "范围for遍历: ";
for (const auto& elem : s)
{
std::cout << elem << " ";
}
std::cout << std::endl;
}
void traverseWithConstIterator(const std::set<int>& s)
{
std::cout << "const_iterator遍历: ";
for (auto it = s.cbegin(); it != s.cend(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
void traverseWithConstReverseIterator(const std::set<int>& s)
{
std::cout << "const_reverse_iterator遍历: ";
for (auto it = s.crbegin(); it != s.crend(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
void demoTraverse()
{
std::cout << "\\n===== 遍历操作 =====" << std::endl;
std::set<int> travSet = { 5, 3, 8, 1, 9, 2, 7 };
traverseForward(travSet);
traverseBackward(travSet);
traverseRangeFor(travSet);
traverseWithConstIterator(travSet);
traverseWithConstReverseIterator(travSet);
}
2.7 容量操作
使用说明:size 获取当前元素数量;empty 判断是否为空,比 size() == 0 语义更清晰且在某些容器上效率更高;max_size 返回理论上限,实际可用内存通常远小于此值,一般仅用于参考。
void capacityInfo(const std::set<int>& s)
{
std::cout << "size: " << s.size() << std::endl;
std::cout << "empty: " << (s.empty() ? "true" : "false") << std::endl;
std::cout << "max_size: " << s.max_size() << std::endl;
}
void demoCapacity()
{
std::cout << "\\n===== 容量操作 =====" << std::endl;
std::set<int> travSet = { 5, 3, 8, 1, 9, 2, 7 };
std::cout << "— 非空集合 —" << std::endl;
capacityInfo(travSet);
std::set<int> emptySet;
std::cout << "— 空集合 —" << std::endl;
capacityInfo(emptySet);
}
2.8 交换操作
使用说明:swap 仅交换两个集合的内部指针,时间复杂度 O(1),不涉及元素拷贝或移动。常用于实现 copy-and-swap 惯用法,或在需要快速置换两个容器内容时使用。交换后两个集合的比较器也必须兼容。
void swapSets(std::set<int>& s1, std::set<int>& s2)
{
s1.swap(s2);
std::cout << "交换完成" << std::endl;
}
void demoSwap()
{
std::cout << "\\n===== 交换操作 =====" << std::endl;
std::set<int> swapA = { 1, 2, 3 };
std::set<int> swapB = { 10, 20, 30, 40 };
std::cout << "交换前 swapA: ";
for (const auto& v : swapA) std::cout << v << " ";
std::cout << std::endl;
std::cout << "交换前 swapB: ";
for (const auto& v : swapB) std::cout << v << " ";
std::cout << std::endl;
swapSets(swapA, swapB);
std::cout << "交换后 swapA: ";
for (const auto& v : swapA) std::cout << v << " ";
std::cout << std::endl;
std::cout << "交换后 swapB: ";
for (const auto& v : swapB) std::cout << v << " ";
std::cout << std::endl;
}
2.9 比较操作
使用说明:六个关系运算符按字典序逐元素比较。==/!= 判断内容是否完全相同;</<=/>/>= 按字典序确定大小关系。比较要求两个集合的元素类型和比较器类型相同。常用于排序、去重后的等价性校验等场景。
void compareSets(const std::set<int>& s1, const std::set<int>& s2)
{
std::cout << "s1 == s2: " << (s1 == s2 ? "true" : "false") << std::endl;
std::cout << "s1 != s2: " << (s1 != s2 ? "true" : "false") << std::endl;
std::cout << "s1 < s2: " << (s1 < s2 ? "true" : "false") << std::endl;
std::cout << "s1 <= s2: " << (s1 <= s2 ? "true" : "false") << std::endl;
std::cout << "s1 > s2: " << (s1 > s2 ? "true" : "false") << std::endl;
std::cout << "s1 >= s2: " << (s1 >= s2 ? "true" : "false") << std::endl;
}
void demoCompare()
{
std::cout << "\\n===== 比较操作 =====" << std::endl;
std::set<int> cmpA = { 1, 2, 3 };
std::set<int> cmpB = { 1, 2, 3 };
std::set<int> cmpC = { 1, 2, 4 };
std::cout << "— cmpA{1,2,3} vs cmpB{1,2,3} —" << std::endl;
compareSets(cmpA, cmpB);
std::cout << "— cmpA{1,2,3} vs cmpC{1,2,4} —" << std::endl;
compareSets(cmpA, cmpC);
}
2.10 合并与提取(C++17)
使用说明:merge 将源集合中不重复的元素零拷贝转移到目标集合,重复元素留在源集合中,比逐个 insert 更高效。extract 将节点从集合中摘出但不销毁,可通过 nh.value() 修改键值后重新 insert,是唯一能修改 set 中元素键值的安全方式。
void mergeSets(std::set<int>& dest, std::set<int>& src)
{
#if _MSVC_LANG >= 201703L
dest.merge(src);
std::cout << "合并完成,dest大小: " << dest.size()
<< ", src剩余大小: " << src.size() << std::endl;
#else
std::cout << "merge需要支持C++17" << std::endl;
#endif
}
void extractNode(std::set<int>& s, int value)
{
#if _MSVC_LANG >= 201703L
auto nh = s.extract(value);
if (!nh.empty())
{
std::cout << "提取节点值: " << nh.value() << std::endl;
}
else
{
std::cout << "提取失败,值不存在: " << value << std::endl;
}
#else
std::cout << "extract需要支持C++17" << std::endl;
#endif
}
void extractAndReinsert(std::set<int>& s, int value)
{
#if _MSVC_LANG >= 201703L
auto nh = s.extract(value);
if (!nh.empty())
{
nh.value() = value + 100;
s.insert(std::move(nh));
std::cout << "提取并修改后重新插入: " << (value + 100) << std::endl;
}
#else
std::cout << "extract需要支持C++17" << std::endl;
#endif
}
void demoMergeExtract()
{
std::cout << "\\n===== 合并与提取 (C++17) =====" << std::endl;
std::set<int> mergeDest = { 1, 3, 5, 7 };
std::set<int> mergeSrc = { 2, 3, 4, 5, 6 };
std::cout << "合并前 dest: ";
for (const auto& v : mergeDest) std::cout << v << " ";
std::cout << std::endl;
std::cout << "合并前 src: ";
for (const auto& v : mergeSrc) std::cout << v << " ";
std::cout << std::endl;
mergeSets(mergeDest, mergeSrc);
std::cout << "合并后 dest: ";
for (const auto& v : mergeDest) std::cout << v << " ";
std::cout << std::endl;
std::cout << "合并后 src: ";
for (const auto& v : mergeSrc) std::cout << v << " ";
std::cout << std::endl;
std::cout << "\\n— 提取演示 —" << std::endl;
std::set<int> extractSet = { 10, 20, 30, 40, 50 };
std::cout << "提取前: ";
for (const auto& v : extractSet) std::cout << v << " ";
std::cout << std::endl;
extractNode(extractSet, 30);
extractNode(extractSet, 99);
extractAndReinsert(extractSet, 20);
std::cout << "提取操作后: ";
for (const auto& v : extractSet) std::cout << v << " ";
std::cout << std::endl;
}
2.11 获取比较器
使用说明:key_comp 和 value_comp 返回集合当前使用的比较器副本。对 set 而言两者等价。获取比较器后可在外部手动执行与集合内部一致的比较逻辑,常用于自定义算法中保持排序一致性,或调试时验证排序规则是否符合预期。
void getComparator(const std::set<int, DescendingCompare>& s)
{
auto comp = s.key_comp();
std::cout << "key_comp()(5, 3) = " << (comp(5, 3) ? "true" : "false") << std::endl;
std::cout << "key_comp()(3, 5) = " << (comp(3, 5) ? "true" : "false") << std::endl;
auto vcomp = s.value_comp();
std::cout << "value_comp()(5, 3) = " << (vcomp(5, 3) ? "true" : "false") << std::endl;
}
void demoComparator()
{
std::cout << "\\n===== 获取比较器 =====" << std::endl;
auto descSet = constructWithCustomComparator();
std::cout << "降序集合: ";
for (const auto& v : descSet) std::cout << v << " ";
std::cout << std::endl;
getComparator(descSet);
}
2.12 自定义类类型综合演示
使用说明:以 Student 类为例,展示自定义类型在 set 中的完整使用流程。通过重载 operator< 定义排序规则(分数升序,同分按姓名),利用 emplace 原地构造避免临时对象,验证重复元素的自动去重行为。此模式可推广至任何需要有序唯一集合的业务场景。
void demoClassType()
{
std::cout << "\\n===== 自定义类类型完整演示 =====" << std::endl;
auto s = constructWithClassType();
std::cout << "按分数升序排列:" << std::endl;
for (const auto& stu : s)
{
std::cout << " " << stu << std::endl;
}
std::cout << "\\n插入新学生:" << std::endl;
emplaceElement(s, "Eve", 20, 99.0);
emplaceElement(s, "Frank", 22, 88.0);
std::cout << "插入后:" << std::endl;
for (const auto& stu : s)
{
std::cout << " " << stu << std::endl;
}
}
第三章 完整代码
#include<iostream>
#include<set>
#include<string>
#include<vector>
#include<algorithm>
#include<functional>
class Student
{
private:
std::string name_;
int age_ = 0;
double score_ = 0.0;
public:
Student() : name_(""), age_(0), score_(0.0) { }
Student(const std::string& name, int age, double score)
: name_(name), age_(age), score_(score) { }
bool operator<(const Student& other) const
{
if (score_ != other.score_)
return score_ < other.score_;
return name_ < other.name_;
}
bool operator==(const Student& other) const
{
return name_ == other.name_ &&
age_ == other.age_ &&
score_ == other.score_;
}
friend std::ostream& operator<<(std::ostream& os, const Student& s)
{
os << "Student{name=" << s.name_ << ", age=" << s.age_ << ", score=" << s.score_ << "}";
return os;
}
std::string getName() const { return name_; }
int getAge() const { return age_; }
double getScore() const { return score_; }
};
class DescendingCompare
{
public:
bool operator()(int a, int b) const
{
return a > b;
}
};
std::set<int> constructDefault()
{
std::set<int> s;
return s;
}
std::set<int> constructWithRange(const std::vector<int>& vec)
{
std::set<int> s(vec.begin(), vec.end());
return s;
}
std::set<int> constructWithInitializerList()
{
std::set<int> s = { 5, 3, 8, 1, 9, 3, 5 };
return s;
}
std::set<int> constructCopy(const std::set<int>& src)
{
std::set<int> s(src);
return s;
}
std::set<int> constructMove(std::set<int>&& src)
{
std::set<int> s(std::move(src));
return s;
}
std::set<int, DescendingCompare> constructWithCustomComparator()
{
std::set<int, DescendingCompare> s = { 3, 1, 4, 1, 5, 9, 2, 6 };
return s;
}
std::set<Student> constructWithClassType()
{
std::set<Student> s;
s.insert(Student("Alice", 20, 95.5));
s.insert(Student("Bob", 21, 88.0));
s.insert(Student("Charlie", 19, 92.3));
s.insert(Student("Alice", 22, 85.0));
return s;
}
void demoConstruction()
{
std::cout << "===== 构造与初始化 =====" << std::endl;
auto s1 = constructDefault();
std::cout << "默认构造,size = " << s1.size() << std::endl;
auto s2 = constructWithRange({ 4, 2, 7, 1, 9, 2, 4 });
std::cout << "区间构造: ";
for (const auto& v : s2) std::cout << v << " ";
std::cout << std::endl;
auto s3 = constructWithInitializerList();
std::cout << "初始化列表构造: ";
for (const auto& v : s3) std::cout << v << " ";
std::cout << std::endl;
auto s4 = constructCopy(s3);
std::cout << "拷贝构造: ";
for (const auto& v : s4) std::cout << v << " ";
std::cout << std::endl;
auto s5 = constructMove(std::set<int>{100, 200, 300});
std::cout << "移动构造: ";
for (const auto& v : s5) std::cout << v << " ";
std::cout << std::endl;
auto s6 = constructWithCustomComparator();
std::cout << "自定义比较器(降序)构造: ";
for (const auto& v : s6) std::cout << v << " ";
std::cout << std::endl;
auto s7 = constructWithClassType();
std::cout << "自定义类类型构造:" << std::endl;
for (const auto& stu : s7) std::cout << " " << stu << std::endl;
}
void insertSingle(std::set<int>& s, int value)
{
auto result = s.insert(value);
if (result.second)
{
std::cout << "插入成功: " << value << std::endl;
}
else
{
std::cout << "插入失败(已存在): " << value << std::endl;
}
}
void insertWithHint(std::set<int>& s, int value)
{
auto hint = s.begin();
auto it = s.insert(hint, value);
std::cout << "提示插入: " << *it << std::endl;
}
void insertRange(std::set<int>& s, const std::vector<int>& vec)
{
s.insert(vec.begin(), vec.end());
std::cout << "区间插入完成,当前大小: " << s.size() << std::endl;
}
void insertInitializerList(std::set<int>& s)
{
s.insert({ 10, 20, 30, 40, 50 });
std::cout << "初始化列表插入完成,当前大小: " << s.size() << std::endl;
}
void emplaceElement(std::set<Student>& s, const std::string& name, int age, double score)
{
auto result = s.emplace(name, age, score);
if (result.second)
{
std::cout << "emplace成功: " << *result.first << std::endl;
}
else
{
std::cout << "emplace失败(已存在): " << *result.first << std::endl;
}
}
void emplaceHintElement(std::set<int>& s, int value)
{
auto hint = s.upper_bound(value);
auto it = s.emplace_hint(hint, value);
std::cout << "emplace_hint插入: " << *it << std::endl;
}
void demoInsert()
{
std::cout << "\\n===== 插入操作 =====" << std::endl;
std::set<int> insertSet = { 1, 3, 5, 7, 9 };
std::cout << "初始集合: ";
for (const auto& v : insertSet) std::cout << v << " ";
std::cout << std::endl;
insertSingle(insertSet, 4);
insertSingle(insertSet, 5);
insertWithHint(insertSet, 6);
insertRange(insertSet, { 11, 13, 15 });
insertInitializerList(insertSet);
std::cout << "最终集合: ";
for (const auto& v : insertSet) std::cout << v << " ";
std::cout << std::endl;
std::cout << "\\n— emplace演示 —" << std::endl;
std::set<Student> studentSet;
emplaceElement(studentSet, "David", 23, 91.0);
emplaceElement(studentSet, "David", 23, 91.0);
std::cout << "\\n— emplace_hint演示 —" << std::endl;
std::set<int> emplaceSet = { 10, 20, 30 };
emplaceHintElement(emplaceSet, 25);
std::cout << "emplace_hint后集合: ";
for (const auto& v : emplaceSet) std::cout << v << " ";
std::cout << std::endl;
}
bool eraseByValue(std::set<int>& s, int value)
{
size_t count = s.erase(value);
return count > 0;
}
void eraseByIterator(std::set<int>& s, int value)
{
auto it = s.find(value);
if (it != s.end())
{
s.erase(it);
std::cout << "通过迭代器删除: " << value << std::endl;
}
}
void eraseByRange(std::set<int>& s, int low, int high)
{
auto itLow = s.lower_bound(low);
auto itHigh = s.upper_bound(high);
s.erase(itLow, itHigh);
std::cout << "区间删除 [" << low << ", " << high << "] 完成" << std::endl;
}
void clearAll(std::set<int>& s)
{
s.clear();
std::cout << "清空完成,当前大小: " << s.size() << std::endl;
}
void traverseForward(const std::set<int>& s);
void demoErase()
{
std::cout << "\\n===== 删除操作 =====" << std::endl;
std::set<int> eraseSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::cout << "初始集合: ";
for (const auto& v : eraseSet) std::cout << v << " ";
std::cout << std::endl;
bool r1 = eraseByValue(eraseSet, 5);
std::cout << "eraseByValue(5) 结果: " << (r1 ? "true" : "false") << std::endl;
bool r2 = eraseByValue(eraseSet, 99);
std::cout << "eraseByValue(99) 结果: " << (r2 ? "true" : "false") << std::endl;
eraseByIterator(eraseSet, 3);
eraseByRange(eraseSet, 6, 8);
traverseForward(eraseSet);
clearAll(eraseSet);
}
bool findByValue(const std::set<int>& s, int value)
{
auto it = s.find(value);
if (it != s.end())
{
std::cout << "找到: " << *it << std::endl;
return true;
}
std::cout << "未找到: " << value << std::endl;
return false;
}
size_t countValue(const std::set<int>& s, int value)
{
size_t cnt = s.count(value);
std::cout << "值 " << value << " 出现次数: " << cnt << std::endl;
return cnt;
}
void lowerBoundDemo(const std::set<int>& s, int value)
{
auto it = s.lower_bound(value);
if (it != s.end())
{
std::cout << "lower_bound(" << value << ") = " << *it << std::endl;
}
else
{
std::cout << "lower_bound(" << value << ") = end()" << std::endl;
}
}
void upperBoundDemo(const std::set<int>& s, int value)
{
auto it = s.upper_bound(value);
if (it != s.end())
{
std::cout << "upper_bound(" << value << ") = " << *it << std::endl;
}
else
{
std::cout << "upper_bound(" << value << ") = end()" << std::endl;
}
}
void equalRangeDemo(const std::set<int>& s, int value)
{
auto range = s.equal_range(value);
std::cout << "equal_range(" << value << "): [";
for (auto it = range.first; it != range.second; it++)
{
std::cout << *it << " ";
}
std::cout << "]" << std::endl;
}
bool containsValue(const std::set<int>& s, int value)
{
#if _MSVC_LANG >= 202002L
bool result = s.contains(value);
std::cout << "contains(" << value << ") = " << (result ? "true" : "false") << std::endl;
return result;
#else
std::cout << "需要支持C++20" << std::endl;
return false;
#endif
}
void demoFind()
{
std::cout << "\\n===== 查找操作 =====" << std::endl;
std::set<int> findSet = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
std::cout << "集合: ";
for (const auto& v : findSet) std::cout << v << " ";
std::cout << std::endl;
findByValue(findSet, 50);
findByValue(findSet, 55);
countValue(findSet, 30);
countValue(findSet, 35);
lowerBoundDemo(findSet, 45);
lowerBoundDemo(findSet, 50);
upperBoundDemo(findSet, 50);
upperBoundDemo(findSet, 100);
equalRangeDemo(findSet, 60);
containsValue(findSet, 70);
containsValue(findSet, 75);
}
void traverseForward(const std::set<int>& s)
{
std::cout << "正向遍历: ";
for (auto it = s.begin(); it != s.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
void traverseBackward(const std::set<int>& s)
{
std::cout << "反向遍历: ";
for (auto it = s.rbegin(); it != s.rend(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
void traverseRangeFor(const std::set<int>& s)
{
std::cout << "范围for遍历: ";
for (const auto& elem : s)
{
std::cout << elem << " ";
}
std::cout << std::endl;
}
void traverseWithConstIterator(const std::set<int>& s)
{
std::cout << "const_iterator遍历: ";
for (auto it = s.cbegin(); it != s.cend(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
void traverseWithConstReverseIterator(const std::set<int>& s)
{
std::cout << "const_reverse_iterator遍历: ";
for (auto it = s.crbegin(); it != s.crend(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
}
void demoTraverse()
{
std::cout << "\\n===== 遍历操作 =====" << std::endl;
std::set<int> travSet = { 5, 3, 8, 1, 9, 2, 7 };
traverseForward(travSet);
traverseBackward(travSet);
traverseRangeFor(travSet);
traverseWithConstIterator(travSet);
traverseWithConstReverseIterator(travSet);
}
void capacityInfo(const std::set<int>& s)
{
std::cout << "size: " << s.size() << std::endl;
std::cout << "empty: " << (s.empty() ? "true" : "false") << std::endl;
std::cout << "max_size: " << s.max_size() << std::endl;
}
void demoCapacity()
{
std::cout << "\\n===== 容量操作 =====" << std::endl;
std::set<int> travSet = { 5, 3, 8, 1, 9, 2, 7 };
std::cout << "— 非空集合 —" << std::endl;
capacityInfo(travSet);
std::set<int> emptySet;
std::cout << "— 空集合 —" << std::endl;
capacityInfo(emptySet);
}
void swapSets(std::set<int>& s1, std::set<int>& s2)
{
s1.swap(s2);
std::cout << "交换完成" << std::endl;
}
void demoSwap()
{
std::cout << "\\n===== 交换操作 =====" << std::endl;
std::set<int> swapA = { 1, 2, 3 };
std::set<int> swapB = { 10, 20, 30, 40 };
std::cout << "交换前 swapA: ";
for (const auto& v : swapA) std::cout << v << " ";
std::cout << std::endl;
std::cout << "交换前 swapB: ";
for (const auto& v : swapB) std::cout << v << " ";
std::cout << std::endl;
swapSets(swapA, swapB);
std::cout << "交换后 swapA: ";
for (const auto& v : swapA) std::cout << v << " ";
std::cout << std::endl;
std::cout << "交换后 swapB: ";
for (const auto& v : swapB) std::cout << v << " ";
std::cout << std::endl;
}
void compareSets(const std::set<int>& s1, const std::set<int>& s2)
{
std::cout << "s1 == s2: " << (s1 == s2 ? "true" : "false") << std::endl;
std::cout << "s1 != s2: " << (s1 != s2 ? "true" : "false") << std::endl;
std::cout << "s1 < s2: " << (s1 < s2 ? "true" : "false") << std::endl;
std::cout << "s1 <= s2: " << (s1 <= s2 ? "true" : "false") << std::endl;
std::cout << "s1 > s2: " << (s1 > s2 ? "true" : "false") << std::endl;
std::cout << "s1 >= s2: " << (s1 >= s2 ? "true" : "false") << std::endl;
}
void demoCompare()
{
std::cout << "\\n===== 比较操作 =====" << std::endl;
std::set<int> cmpA = { 1, 2, 3 };
std::set<int> cmpB = { 1, 2, 3 };
std::set<int> cmpC = { 1, 2, 4 };
std::cout << "— cmpA{1,2,3} vs cmpB{1,2,3} —" << std::endl;
compareSets(cmpA, cmpB);
std::cout << "— cmpA{1,2,3} vs cmpC{1,2,4} —" << std::endl;
compareSets(cmpA, cmpC);
}
void mergeSets(std::set<int>& dest, std::set<int>& src)
{
#if _MSVC_LANG >= 201703L
dest.merge(src);
std::cout << "合并完成,dest大小: " << dest.size()
<< ", src剩余大小: " << src.size() << std::endl;
#else
std::cout << "merge需要支持C++17" << std::endl;
#endif
}
void extractNode(std::set<int>& s, int value)
{
#if _MSVC_LANG >= 201703L
auto nh = s.extract(value);
if (!nh.empty())
{
std::cout << "提取节点值: " << nh.value() << std::endl;
}
else
{
std::cout << "提取失败,值不存在: " << value << std::endl;
}
#else
std::cout << "extract需要支持C++17" << std::endl;
#endif
}
void extractAndReinsert(std::set<int>& s, int value)
{
#if _MSVC_LANG >= 201703L
auto nh = s.extract(value);
if (!nh.empty())
{
nh.value() = value + 100;
s.insert(std::move(nh));
std::cout << "提取并修改后重新插入: " << (value + 100) << std::endl;
}
#else
std::cout << "extract需要支持C++17" << std::endl;
#endif
}
void demoMergeExtract()
{
std::cout << "\\n===== 合并与提取 (C++17) =====" << std::endl;
std::set<int> mergeDest = { 1, 3, 5, 7 };
std::set<int> mergeSrc = { 2, 3, 4, 5, 6 };
std::cout << "合并前 dest: ";
for (const auto& v : mergeDest) std::cout << v << " ";
std::cout << std::endl;
std::cout << "合并前 src: ";
for (const auto& v : mergeSrc) std::cout << v << " ";
std::cout << std::endl;
mergeSets(mergeDest, mergeSrc);
std::cout << "合并后 dest: ";
for (const auto& v : mergeDest) std::cout << v << " ";
std::cout << std::endl;
std::cout << "合并后 src: ";
for (const auto& v : mergeSrc) std::cout << v << " ";
std::cout << std::endl;
std::cout << "\\n— 提取演示 —" << std::endl;
std::set<int> extractSet = { 10, 20, 30, 40, 50 };
std::cout << "提取前: ";
for (const auto& v : extractSet) std::cout << v << " ";
std::cout << std::endl;
extractNode(extractSet, 30);
extractNode(extractSet, 99);
extractAndReinsert(extractSet, 20);
std::cout << "提取操作后: ";
for (const auto& v : extractSet) std::cout << v << " ";
std::cout << std::endl;
}
void getComparator(const std::set<int, DescendingCompare>& s)
{
auto comp = s.key_comp();
std::cout << "key_comp()(5, 3) = " << (comp(5, 3) ? "true" : "false") << std::endl;
std::cout << "key_comp()(3, 5) = " << (comp(3, 5) ? "true" : "false") << std::endl;
auto vcomp = s.value_comp();
std::cout << "value_comp()(5, 3) = " << (vcomp(5, 3) ? "true" : "false") << std::endl;
}
void demoComparator()
{
std::cout << "\\n===== 获取比较器 =====" << std::endl;
auto descSet = constructWithCustomComparator();
std::cout << "降序集合: ";
for (const auto& v : descSet) std::cout << v << " ";
std::cout << std::endl;
getComparator(descSet);
}
void demoClassType()
{
std::cout << "\\n===== 自定义类类型完整演示 =====" << std::endl;
auto s = constructWithClassType();
std::cout << "按分数升序排列:" << std::endl;
for (const auto& stu : s)
{
std::cout << " " << stu << std::endl;
}
std::cout << "\\n插入新学生:" << std::endl;
emplaceElement(s, "Eve", 20, 99.0);
emplaceElement(s, "Frank", 22, 88.0);
std::cout << "插入后:" << std::endl;
for (const auto& stu : s)
{
std::cout << " " << stu << std::endl;
}
}
int main()
{
demoConstruction();
demoInsert();
demoErase();
demoFind();
demoTraverse();
demoCapacity();
demoSwap();
demoCompare();
demoMergeExtract();
demoComparator();
demoClassType();
return 0;
}


