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.mzph.cn/news/901954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SSM省市区三级联动和三表联查附带数据库

SSM省市区三级联动和三表联查 ------附带数据库码云地址&#xff1a;https://gitee.com/Mr_ZKC/NO1 数据库在项目中

曲棍球·棒球1号位

中国女子曲棍球队曾涌现过马弋博、李红侠等优秀选手&#xff0c;但“李红”这一名字可能为信息误差。以下为您系统介绍曲棍球&#xff0c;并结合棒球进行对比分析&#xff1a; 曲棍球&#xff08;Hockey&#xff09;核心特点 运动形式 分为草地曲棍球&#xff08;夏季奥运会项…

12芯束装光纤不同包层线颜色之间的排列顺序

为什么光纤线必须按照以下颜色顺序进行排序&#xff1f;这其实是为了防止光污染的问题&#xff0c;不同颜色在传递光时从包层表皮漏光传感到梳妆的其它纤芯上&#xff0c;会有光污染的问题&#xff0c;而为了减少并防止光污染的现象&#xff0c;所以在光通信之中&#xff0c;需…

c++程序的打包编译cmake+make

c打包编译 1 在不用系统中打包介绍1.1 linux中打包c程序的2种方式1.2 windows中打包c程序1.3 cmakeNinja和cmakemake的两种方式对比1.3.1 Ninja是什么&#xff08;可以认为是make工具的一个替代产品&#xff09;1.3.2 cmakeNinja可以用于linux和windows系统中&#xff0c;编译效…

Spark on K8s 在 vivo 大数据平台的混部实战与优化

一、Spark on K8s 简介 (一)定义与架构 Spark on K8s 是一种将 Spark 运行在 Kubernetes(K8s)集群上的架构,由 K8s 直接创建 Driver 和 Executor 的 Pod 来运行 Spark 作业。其架构如下。 Driver Pod:相当于 Spark 集群中的 Driver,负责作业的调度和管理,它会根据作业…

MDA测量数据查看器【内含工具和源码地址】

一、工具介绍 MDA测量数据查看器用于显示和分析以MDF格式提供的测量数据。 支持MDF3.3之前含MDF3.3的二进制格式&#xff0c;支持Vector CANape and ETAS Inca. Kvaser CAN Logger (MDF 3.2) 文件。 MDF (Measurement Data Format)是一种二进制文件&#xff0c;用来记录、交换…

番外篇 | SEAM-YOLO:引入SEAM系列注意力机制,提升遮挡小目标的检测性能

前言:Hello大家好,我是小哥谈。SEAM(Squeeze-and-Excitation Attention Module)系列注意力机制是一种高效的特征增强方法,特别适合处理遮挡和小目标检测问题。该机制通过建模通道间关系来自适应地重新校准通道特征响应。在遮挡小目标检测中的应用优势包括:1)通道注意力增强…

使用VHDL语言实现TXT文件的读写操作

使用FPGA进行图像处理时&#xff0c;通常需要将TXT文件中的图像数据读出到TestBench中&#xff0c;并将仿真的结果写入到TXT文件中&#xff0c;用于确认图像处理的结果是否正确。 VHDL中TXT文件的读写操作如下所示&#xff0c; --------------------------------------------…

基于Redis的4种延时队列实现方式

延时队列是一种特殊的消息队列&#xff0c;它允许消息在指定的时间后被消费。在微服务架构、电商系统和任务调度场景中&#xff0c;延时队列扮演着关键角色。例如&#xff0c;订单超时自动取消、定时提醒、延时支付等都依赖延时队列实现。 Redis作为高性能的内存数据库&#x…

GN ninja 工程化构建例程

文章目录 1. 前言✨2. 工程实例🚩2.1 工程目录结构2.2 工程顶层.gn文件2.3 工具链配置.gn文件2.4 编译配置.gn文件2.5 编译目标配置.gn文件2.6 工程接口文件2.7 动态库编译.gn文件2.8 动态库源文件2.9 静态库编译.gn文件2.10 静态库源文件2.11 主程序编译.gn文件2.12 主程序源…

基于亚博K210开发板——内存卡读写文件

开发板 亚博K210开发板 实验目的 本实验主要学习 K210 通过 SPI 读写内存卡文件的功能 实验准备 实验元件 开发板自带的 TF 卡、LCD 显示屏 &#xff08;提前准备好 FAT32 格式的TF 卡。TF 插入 TF 卡槽的时候注意方向&#xff0c;TF 卡的金手指那一面需要面向开发板&am…

51单片机实验五:A/D和D/A转换

一、实验环境与实验器材 环境&#xff1a;Keli&#xff0c;STC-ISP烧写软件,Proteus. 器材&#xff1a;TX-1C单片机&#xff08;STC89C52RC&#xff09;、电脑。 二、 实验内容及实验步骤 1.A/D转换 概念&#xff1a;模数转换是将连续的模拟信号转换为离散的数字信…

C++ 常用的智能指针

C 智能指针 一、智能指针类型概览 C 标准库提供以下智能指针&#xff08;需包含头文件 <memory>&#xff09;&#xff1a; unique_ptr&#xff1a;独占所有权&#xff0c;不可复制&#xff0c; 可移动shared_ptr&#xff1a;共享所有权&#xff0c;用于引用计数weak_pt…

6.8.最小生成树

一.复习&#xff1a; 1.生成树&#xff1a; 对于一个连通的无向图&#xff0c;假设图中有n个顶点&#xff0c;如果能找到一个符合以下要求的子图&#xff1a; 子图中包含图中所有的顶点&#xff0c;同时各个顶点保持连通&#xff0c; 而且子图的边的数量只有n-1条&#xff0…

Spring Boot 集成金蝶 API 演示

✨ Spring Boot 集成金蝶 API 演示&#xff1a;登录 / 注销 Cookie 保存 本文将通过 Spring Boot 完整实现一套金蝶接口集成模型&#xff0c;包括&#xff1a; ✅ 普通登录✅ AppSecret 登录✅ 注销✅ Cookie 保存与复用 &#x1f4c5; 项目结构 src/ ├── controller/ │…

React 受控表单绑定基础

React 中最常见的几个需求是&#xff1a; 渲染一组列表绑定点击事件表单数据与组件状态之间的绑定 受控表单绑定是理解表单交互的关键之一。 &#x1f4cd;什么是受控组件&#xff1f; 在 React 中&#xff0c;所谓“受控组件”&#xff0c;指的是表单元素&#xff08;如 &l…

基于FPGA的AES加解密系统verilog实现,包含testbench和开发板硬件测试

目录 1.课题概述 2.系统测试效果 3.核心程序与模型 4.系统原理简介 4.1 字节替换&#xff08;SubBytes&#xff09; 4.2 行移位&#xff08;ShiftRows&#xff09; 4.3 列混合&#xff08;MixColumns&#xff09; 4.4 轮密钥加&#xff08;AddRoundKey&#xff09; 4.…

6.5 GitHub监控系统实战:双通道采集+动态调度打造高效运维体系

GitHub Sentinel Agent 定期更新功能设计与实现 关键词:GitHub API 集成、定时任务调度、Python 爬虫开发、SMTP 邮件通知、系统稳定性保障 1. GitHub 项目数据获取功能 1.1 双通道数据采集架构设计 #mermaid-svg-ZHJIMXcMAyDHVhmV {font-family:"trebuchet ms",v…

Explorer++:轻量级高效文件管理器!!

项目简介 Explorer 是一款专为Windows操作系统设计的轻量级且高效的文件管理器。作为Windows资源管理器的强大替代方案&#xff0c;它提供了丰富的特性和优化的用户体验&#xff0c;使得文件管理和组织变得更加便捷高效。无论是专业用户还是普通用户&#xff0c;都能从中受益&a…