深入解析C++标准库中的std::set容器

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 的集合操作。
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值