当前位置: 首页 > ds >正文

std::set (C++)

std::set

  • 1. 概述
    • 定义
    • 特点
  • 2. 内部实现
  • 3. 性能特征
  • 4. 常用 API
  • 5. 使用示例
  • 6. 自定义比较器
  • 7. 注意事项与优化
  • 8. 使用建议

1. 概述

定义

template<class Key,class Compare = std::less<Key>,class Allocator = std::allocator<Key>
>
class std::set;

特点

  • 有序:所有元素按严格弱序(由 Compare 决定)排列,不保证相同键的重复出现(键唯一)。

  • 唯一键:插入时如果集合中已有相同元素,不会增加新的节点。

  • 底层结构:通常基于红黑树(balanced binary search tree)实现。

2. 内部实现

  1. 红黑树

    • 平衡二叉查找树,保证从根到任一叶子路径的“黑色节点数”相同,从而令树高度为 O(log n)。
  2. 节点结构

    • 每个节点存储:
      • 元素值 Key
      • 左/右子指针和父指针
      • 一个颜色标记(红或黑)
  3. 拷贝与移动

    • 拷贝时会对整棵树进行深拷贝;移动构造则接管底层指针,无需逐节点复制。

3. 性能特征

操作平均复杂度最坏复杂度备注
insertO(log n)O(log n)包括查找插入位置与调整平衡
eraseO(log n)O(log n)按键删除时需旋转与重着色
findO(log n)O(log n)
clearO(n)O(n)释放所有节点
遍历O(n)O(n)中序遍历即可
  • 内存开销:

    • 每个节点需存储三个指针(左右、父)和一个颜色字段,相比哈希表更紧凑但比 std::vector 等顺序容器要高。
  • 迭代器失效规则:

    • 插入和删除会使仅被删除的节点的迭代器失效,其他节点迭代器保持有效。

4. 常用 API

// 构造与析构
std::set<Key> s1;                             // 默认构造
std::set<Key> s2({k1, k2, k3});               // 初始化列表
std::set<Key, Compare> s3(comp);              // 指定比较器// 大小与容量
bool empty() const noexcept;
size_t size() const noexcept;
size_t max_size() const noexcept;// 元素访问
iterator find(const Key& key);
size_t count(const Key& key) const;           // 要么 0,要么 1// 插入
std::pair<iterator,bool> insert(const Key& key);
iterator insert(iterator hint, const Key& key);
template<class... Args>
std::pair<iterator,bool> emplace(Args&&... args);// 删除
size_t erase(const Key& key);
iterator erase(iterator pos);
iterator erase(iterator first, iterator last);// 遍历
iterator begin() noexcept;
iterator end() noexcept;
const_iterator cbegin() const noexcept;
const_iterator cend() const noexcept;// 有序查询
iterator lower_bound(const Key& key);         // ≥ key 的第一个位置
iterator upper_bound(const Key& key);         // > key 的第一个位置
std::pair<iterator,iterator> equal_range(const Key& key);// 比较器与分配器访问
Compare key_comp() const;
Compare value_comp() const;                   // 同 key_comp
Allocator get_allocator() const noexcept;// 交换
void swap(std::set& other) noexcept;

5. 使用示例

#include <set>
#include <iostream>int main() {std::set<int> s;// 插入s.insert(3);s.emplace(1);s.insert({5, 2, 4});// 查找if (s.find(2) != s.end()) {std::cout << "2 存在\n";}// 遍历(中序:1,2,3,4,5)for (int x : s) {std::cout << x << " ";}std::cout << "\n";// 有序查询auto it = s.lower_bound(3);  // 指向 3std::cout << "lower_bound(3): " << *it << "\n";// 删除s.erase(3);                  // 删除值为 3 的节点// 范围删除s.erase(s.begin(), s.lower_bound(4)); // 删除所有 <4 的元素// 清空s.clear();
}

6. 自定义比较器

当需要自定义排序规则(如降序或复合键)时,可提供自定义比较器:

struct Desc {bool operator()(int a, int b) const {return a > b;  // 降序}
};std::set<int, Desc> s_desc;  // 插入后,将按从大到小顺序存储

对于复合类型:

struct Person {std::string name;int age;
};struct ByAgeName {bool operator()(Person const& a, Person const& b) const {if (a.age != b.age) return a.age < b.age;return a.name < b.name;}
};// 年龄升序,若年龄相同则按名字升序
std::set<Person, ByAgeName> roster;

7. 注意事项与优化

  1. 避免不必要的拷贝

    • insert(const Key&) 会拷贝一次;若可移动,优先使用 insert(Key&&) 或 emplace()。
  2. hint 参数

    • insert(hint, key):若能提供一个接近正确位置的迭代器 hint,可将插入复杂度降到常数时间。
  3. 批量插入

    • 对初始化列表或范围插入,建议先 reserve()(C++23 起支持)或构造时传入范围,以减少重平衡次数。
  4. 避免迭代器失效

    • 删除或插入仅影响相关节点迭代器,其他迭代器保持有效。

8. 使用建议

  • 适用场景

    • 需要自动排序且元素唯一时,首选 std::set。
    • 需要查询前驱/后继、区间操作(lower_bound、upper_bound、中序遍历)时非常方便。
  • 不适用场景

    • 需要允许重复键或多对一映射时,改用 std::multiset 或 std::map。
    • 对性能有极致要求且不在意顺序时,可考虑 std::unordered_set(哈希实现,平均 O(1))。
http://www.xdnf.cn/news/267.html

相关文章:

  • #手动控制windows更新时间(非常安全,可随时恢复)
  • C++ 网络层接口设计与实现:基于 Socket 编程
  • L2-018 多项式A除以B
  • SQL-exists和in核心区别​、 性能对比​、适用场景​
  • 2.1 数据处理
  • 【 解决Cline插件无法激活及DeepSeek模型请求卡顿或者无法加载问题】
  • CMake使用教程
  • IO流(二)
  • 从 Transformer 到文本生成 (From Transformer to Text Generation)
  • STM32---GPIO
  • Linux——进程通信
  • Spring MVC 初体验~~
  • 自定义 el-menu
  • 【jenkins】首次配置jenkins
  • 合成数据中的对抗样本生成与应用:让AI模型更强、更稳、更安全
  • 代码学习总结(五)
  • cmake 语法大纲
  • 研究生面试常见问题
  • 1.Linux基础指令
  • 卷积神经网络(CNN)与VGG16在图像识别中的实验设计与思路
  • docker镜像被覆盖了怎么办?通过sha256重新上传镜像
  • VueRouter笔记
  • 6. 实战(二):用Spring AI+OpenAI构建企业级智能客服
  • LeetCode19.删除链表的倒数第N个节点
  • OpenCV图像加密和解密
  • PGSql常用操作命令
  • OBS 日期时间.毫秒时间脚本 date-and-time.lua
  • 该文件没有与之关联的程序来执行此操作
  • 图像预处理-图像噪点消除
  • 【人工智能】DeepSeek 与 RAG 技术:构建知识增强型问答系统的实战