1. 底层实现
std::set
是一个有序的集合,底层通常由 红黑树(Red-Black Tree)实现。这是一种自平衡二叉搜索树,能够在插入、删除和查找操作时保持平衡,从而确保这些操作的时间复杂度为 O(logn)。
2. 缺点和相同功能其他容器对比
缺点:
- 空间开销较大:由于红黑树节点包含额外的颜色和指向子节点的指针,其空间开销较大。
- 插入和删除性能不如哈希表:相比
std::unordered_set
(哈希表),插入和删除操作的性能稍逊,尽管是有序的。 - 迭代性能较低:相对于线性数据结构(如
std::vector
或std::list
),其迭代性能会稍逊。
与其他容器对比:
-
std::set
vs.std::unordered_set
:std::unordered_set
是无序的,基于哈希表实现。- 优点:
std::unordered_set
的查找、插入和删除操作平均时间复杂度为 O(1)。 - 缺点:
std::unordered_set
没有自动排序功能。 - 应用场景:
std::unordered_set
适用于不需要顺序且对速度要求较高的场景。
-
std::set
vs.std::map
:std::map
是一个键值对(key-value pair)容器,而std::set
只是存储键。- 应用场景:当只需要存储唯一键时,
std::set
更合适;需要键值对存储时,std::map
是更好的选择。
-
std::set
vs.std::multiset
:std::multiset
允许存储重复的键。- 应用场景:当需要存储重复键时,
std::multiset
比std::set
更合适。
3. 优点和使用场景
优点:
- 自动排序:插入的元素会自动按排序规则排好序。
- 高效查找:基于红黑树的实现,保证了插入、删除和查找操作的时间复杂度为 O(logn)。
- 唯一性:
std::set
保证容器内的元素唯一,不包含重复元素。
使用场景:
- 有序集合:需要按顺序存储和访问唯一元素的场景,如排名列表。
- 高效集合操作:需要进行集合操作(如交集、并集和差集)时。
- 快速查找:需要快速查找和移除元素的场景。
4. 补充和代码示例
补充:
- 自定义比较函数:可以通过提供自定义比较函数来定制元素的排序方式。
- 迭代器稳定性:插入和删除操作不会使现有的迭代器失效,除了指向被删除元素的迭代器。
代码示例:
以下是一个关于 std::set
使用的示例,包括插入、删除、查找、遍历和集合操作:
#include <iostream>
#include <set>
int main() {
// 创建一个 std::set,默认根据元素自身的顺序进行排序
std::set<int> mySet;
// 插入元素
mySet.insert(5);
mySet.insert(3);
mySet.insert(8);
mySet.insert(1);
// 打印 set 中的元素
std::cout << "Set elements:" << std::endl;
for (const auto& elem : mySet) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 查找某个元素
auto it = mySet.find(3);
if (it != mySet.end()) {
std::cout << "Found element: " << *it << std::endl;
} else {
std::cout << "Element not found." << std::endl;
}
// 删除某个元素
mySet.erase(3);
// 打印删除后的 set
std::cout << "Set after erasing element 3:" << std::endl;
for (const auto& elem : mySet) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 使用 lower_bound 和 upper_bound
auto lb = mySet.lower_bound(2); // 找到第一个>=2 的元素
auto ub = mySet.upper_bound(5); // 找到第一个>5的元素
std::cout << "Lower bound for 2: " << (lb != mySet.end() ? std::to_string(*lb) : "not found") << std::endl;
std::cout << "Upper bound for 5: " << (ub != mySet.end() ? std::to_string(*ub) : "not found") << std::endl;
// 创建并集、交集、差集
std::set<int> set1 = {1, 2, 3};
std::set<int> set2 = {3, 4, 5};
// 并集
std::set<int> unionSet;
std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::inserter(unionSet, unionSet.begin()));
std::cout << "Union of set1 and set2: ";
for (const auto& elem : unionSet) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 交集
std::set<int> intersectionSet;
std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), std::inserter(intersectionSet, intersectionSet.begin()));
std::cout << "Intersection of set1 and set2: ";
for (const auto& elem : intersectionSet) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 差集
std::set<int> differenceSet;
std::set_difference(set1.begin(), set1.end(), set2.begin(), set2.end(), std::inserter(differenceSet, differenceSet.begin()));
std::cout << "Difference of set1 and set2: ";
for (const auto& elem : differenceSet) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
在这个示例中,我们展示了:
- 创建并插入元素到
std::set
中。 - 遍历及打印
std::set
中的元素。 - 查找某个元素。
- 删除某个元素。
- 使用
lower_bound
和upper_bound
进行范围操作。 - 进行并集、交集和差集操作,展示了
std::set
的集合操作。