std::set是以key为元素的关联容器,容器中的key是唯一的且按顺序排列的。搜索、移除和插入的时间复杂度是 。底层通常是以红黑树实现的。
template<
class Key,
class Compare = std::less,
class Allocator = std::allocator
> class set;
本文章的代码库:
https://gitee.com/gamestorm577/CppStd
可以用迭代器、另一个set或者元素列表来构造一个set。代码示例:
auto print_func = [](const std::set& set)
{
for (auto i : set)
{
std::cout << i << " ";
}
std::cout << std::endl;
};
std::vector vec{11, 7, 5, 3, 5, 5, 11};
std::set s1(vec.begin(), vec.end());
std::set s2(s1);
std::set s3{29, 15, 15, 3, 17};
print_func(s1);
print_func(s2);
print_func(s3);
输出结果:
3 5 7 11
3 5 7 11
3 15 17 29
删除set时,会调用各元素的析构函数。代码示例:
struct MyStruct
{
MyStruct(int i)
: Index(i)
{
}
~MyStruct()
{
std::cout << "destruct, Index = " << Index << std::endl;
}
int Index = 0;
};
struct MyStructCmp
{
bool operator()(const MyStruct& lhs, const MyStruct& rhs) const
{
return lhs.Index < rhs.Index;
}
};
std::set s = {7, 3, 17, 3, 9};
std::cout << "end" << std::endl;
输出结果:
destruct, Index = 9
destruct, Index = 3
destruct, Index = 17
destruct, Index = 3
destruct, Index = 7
end
destruct, Index = 3
destruct, Index = 9
destruct, Index = 17
destruct, Index = 7
可以用另一个set或者元素列表给set赋值。代码示例:
std::set tmp{29, 15, 15, 3, 17, 17, 19};
std::set s1;
std::set s2;
s1 = tmp;
s2 = {29, 15, 15, 3, 17, 17, 19};
std::cout << "s1 size = " << s1.size() << std::endl;
std::cout << "s2 size = " << s2.size() << std::endl;
输出结果:
s1 size = 5
s2 size = 5
接口begin、cbegin指向list起始的迭代器,end、cend指向末尾的迭代器。rbegin、crbegin指向起始的逆向迭代器,rend、crend指向末尾的逆向迭代器。无论什么迭代器都不能修改元素的值。代码示例:
std::set s{7, 15, 19, 29, 39};
for (auto iter = s.begin(); iter != s.end(); ++iter)
{
std::cout << "num is: " << *iter << std::endl;
}
输出结果:
num is: 7
num is: 15
num is: 19
num is: 29
num is: 39
检查set是否为空。代码示例:
std::set s1{7, 15, 19, 29, 39};
std::set s2;
std::cout << std::boolalpha;
std::cout << "s1 empty: " << s1.empty() << std::endl;
std::cout << "s2 empty: " << s2.empty() << std::endl;
输出结果:
s1 empty: false
s2 empty: true
获取set中元素的个数。代码示例:
std::set s1{7, 15, 19, 29, 39};
std::set s2;
std::cout << "s1 size = " << s1.size() << std::endl;
std::cout << "s2 size = " << s2.size() << std::endl;
输出结果:
s1 size = 5
s2 size = 0
返回可以容纳的最大元素个数。代码示例:
struct MyStruct
{
double num1;
double num2;
double num3;
double num4;
};
std::set s1;
std::set s2;
std::set s3;
std::cout << "s1 max size = " << s1.max_size() << std::endl;
std::cout << "s2 max size = " << s2.max_size() << std::endl;
std::cout << "s3 max size = " << s3.max_size() << std::endl;
输出结果:
s1 max size = 576460752303423487
s2 max size = 461168601842738790
s3 max size = 288230376151711743
清除所有的元素。代码示例:
std::set s{7, 15, 19, 29, 39};
std::cout << "s size = " << s.size() << std::endl;
s.clear();
std::cout << "s size = " << s.size() << std::endl;
输出结果:
s size = 5
s size = 0
提取一个元素并返回它的句柄,提取完成后set不再拥有该元素。代码示例:
auto print_func = [](const std::set& set)
{
for (auto i : set)
{
std::cout << i << " ";
}
std::cout << std::endl;
};
std::set s{1, 2, 3};
print_func(s);
std::set::node_type node = s.extract(1);
print_func(s);
std::cout << std::boolalpha;
std::cout << "node empty: " << node.empty() << std::endl;
std::cout << "node value: " << node.value() << std::endl;
node.value() = 5;
std::cout << "node value: " << node.value() << std::endl;
插入元素,可以插入元素、迭代器或者节点。代码示例:
auto print_func = [](const std::set& set)
{
for (auto i : set)
{
std::cout << i << " ";
}
std::cout << std::endl;
};
std::vector vec{7, 8, 9};
std::set s{2, 3, 5, 7, 11};
print_func(s);
s.insert(4);
print_func(s);
s.insert(4);
print_func(s);
s.insert(std::next(s.begin(), 1), 19);
print_func(s);
s.insert(vec.begin(), vec.end());
print_func(s);
std::set::node_type node = s.extract(19);
print_func(s);
node.value() = 1;
s.insert(std::move(node));
print_func(s);
输出结果:
2 3 5 7 11
2 3 4 5 7 11
2 3 4 5 7 11
2 3 4 5 7 11 19
2 3 4 5 7 8 9 11 19
2 3 4 5 7 8 9 11
1 2 3 4 5 7 8 9 11
构造一个元素到set中。代码示例:
struct MyStruct
{
MyStruct(float num1, int num2)
{
std::cout << "construct " << num1 << " " << num2 << std::endl;
}
};
struct MyStructCmp
{
bool operator()(const MyStruct&, const MyStruct&) const
{
return true;
}
};
std::set s;
s.emplace(1.5f, 2);
s.emplace(12.1f, 9);
输出结果:
construct 1.5 2
construct 12.1 9
移除指定位置的元素或者移除指定的值。代码示例:
auto print_func = [](const std::set& set)
{
for (auto i : set)
{
std::cout << i << " ";
}
std::cout << std::endl;
};
std::set s{1, 2, 3, 4, 5, 6, 7, 8, 9};
print_func(s);
s.erase(std::next(s.begin(), 2));
print_func(s);
s.erase(std::next(s.begin(), 2), std::next(s.begin(), 5));
print_func(s);
s.erase(8);
print_func(s);
输出结果:
1 2 3 4 5 6 7 8 9
1 2 4 5 6 7 8 9
1 2 7 8 9
1 2 7 9
和另一个set交换元素内容。代码示例:
std::set s1{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::set s2{1, 2, 3};
s1.swap(s2);
std::cout << "s1 size = " << s1.size() << std::endl;
std::cout << "s2 size = " << s2.size() << std::endl;
输出结果:
s1 size = 3
s2 size = 9
合并另一个set或者multiset的元素。代码示例:
auto print_func = [](std::string tag, const std::set& set)
{
std::cout << tag;
for (auto i : set)
{
std::cout << i << " ";
}
std::cout << std::endl;
};
std::set s1{1, 2, 8, 9};
std::set s2{3, 4};
s1.merge(s2);
print_func("s1 = ", s1);
print_func("s2 = ", s2);
输出结果:
s1 = 1 2 3 4 8 9
s2 =
获取元素的数量。由于set的元素是不重复的,结果只能是0或者1。代码示例:
std::set s{1, 2, 8, 9};
std::cout << "elment 1 count = " << s.count(1) << std::endl;
std::cout << "elment 3 count = " << s.count(3) << std::endl;
输出结果:
elment 1 count = 1
elment 3 count = 0
获取元素的位置。代码示例:
std::set s{1, 2, 8, 9};
auto iter1 = s.find(1);
auto iter2 = s.find(3);
std::cout << std::boolalpha;
std::cout << "elment has 1: " << (iter1 == s.end()) << std::endl;
std::cout << "elment has 3: " << (iter2 == s.end()) << std::endl;
输出结果:
elment has 1: false
elment has 3: true
检查是否包含特定的元素。代码示例:
std::set s{1, 2, 8, 9};
std::cout << std::boolalpha;
std::cout << "contain 1: " << s.contains(1) << std::endl;
std::cout << "contain 3: " << s.contains(3) << std::endl;
输出结果:
contain 1: true
contain 3: false
返回两个迭代器,第一个迭代器指向第一个大于等于指定元素的位置,第一个迭代器指向第一个大于指定元素的位置。代码示例:
std::set s{2, 3, 5, 7, 11};
auto [iter1, iter2] = s.equal_range(3);
std::cout << "iter1 is: " << *iter1 << std::endl;
std::cout << "iter2 is: " << *iter2 << std::endl;
auto [iter3, iter4] = s.equal_range(4);
std::cout << "iter3 is: " << *iter3 << std::endl;
std::cout << "iter4 is: " << *iter4 << std::endl;
iter1 is: 3
iter2 is: 5
iter3 is: 5
iter4 is: 5
获取首个大于等于指定元素的位置。代码示例:
std::set s{2, 3, 5, 7, 11};
auto iter1 = s.lower_bound(3);
auto iter2 = s.lower_bound(4);
std::cout << "iter1 is: " << *iter1 << std::endl;
std::cout << "iter2 is: " << *iter2 << std::endl;
输出结果:
iter1 is: 3
iter2 is: 5
获取首个大于指定元素的位置。代码示例:
std::set s{2, 3, 5, 7, 11};
auto iter1 = s.upper_bound(3);
auto iter2 = s.upper_bound(4);
std::cout << "iter1 is: " << *iter1 << std::endl;
std::cout << "iter2 is: " << *iter2 << std::endl;
输出结果:
iter1 is: 5
iter2 is: 5
返回用于比较键值的函数。代码示例:
struct Comp
{
bool operator()(int lhs, int rhs) const
{
std::cout << "Comp" << std::endl;
return lhs < rhs;
}
};
std::set s;
auto comp_func = s.key_comp();
std::cout << std::boolalpha;
std::cout << comp_func(10, 20) << std::endl;
输出结果:
Comp
true
和key_comp相同,返回用于比较键值的函数。
operator==,!=,<,<=,>,>=用于比较两个set。代码示例:
std::set s1 = {2, 3, 5};
std::set s2 = {5, 3, 2};
std::cout << std::boolalpha;
std::cout << "s1 == s2: " << (s1 == s2) << std::endl;
std::cout << "s1 != s2: " << (s1 != s2) << std::endl;
std::cout << "s1 < s2: " << (s1 < s2) << std::endl;
std::cout << "s1 <= s2: " << (s1 <= s2) << std::endl;
std::cout << "s1 > s2: " << (s1 > s2) << std::endl;
std::cout << "s1 >= s2: " << (s1 >= s2) << std::endl;
输出结果:
s1 == s2: true
s1 != s2: false
s1 < s2: false
s1 <= s2: true
s1 > s2: false
s1 >= s2: true
交换两个set的元素内容。示例代码:
std::set s1 = {2, 3, 5};
std::set s2 = {5, 3, 2, 19};
std::swap(s1, s2);
std::cout << "s1 size is: " << s1.size() << std::endl;
std::cout << "s2 size is: " << s2.size() << std::endl;
输出结果:
s1 size is: 4
s2 size is: 3
删除满足条件的元素。代码示例:
std::set s = {2, 3, 5, 7, 11, 13, 17};
std::cout << "s size = " << s.size() << std::endl;
std::erase_if(s,
[](int a)
{
return a > 11;
});
std::cout << "s size = " << s.size() << std::endl;
输出结果:
s size = 7
s size = 5