std::set (C++)

news2025/4/19 18:43:04

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);  // 指向 3
    std::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.coloradmin.cn/o/2338184.html

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

相关文章

RK3588S开发板将SPI1接口改成GPIO

参考官方教程&#xff1a;ROC-RK3588S-PC 一.基本知识&#xff1a; 1.GPIO引脚计算&#xff1a; ROC-RK3588S-PC 有 5 组 GPIO bank&#xff1a;GPIO0~GPIO4&#xff0c;每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分&#xff0c;常用以下公式计算引脚&#xff1a;GPIO…

PLOS ONE:VR 游戏扫描揭示了 ADHD 儿童独特的大脑活动

在孩子的成长过程中&#xff0c;总有那么一些“与众不同”的孩子。他们似乎总是坐不住&#xff0c;课堂上小动作不断&#xff0c;注意力难以集中&#xff0c;作业总是拖拖拉拉……这些行为常常被家长和老师简单地归结为“淘气”“不听话”。然而&#xff0c;他们可能并不只是“…

DemoGen:用于数据高效视觉运动策略学习的合成演示生成

25年2月来自清华、上海姚期智研究院和上海AI实验室的论文“DemoGen: Synthetic Demonstration Generation for Data-Efficient Visuomotor Policy Learning”。 视觉运动策略在机器人操控中展现出巨大潜力&#xff0c;但通常需要大量人工采集的数据才能有效执行。驱动高数据需…

@JsonView + 单一 DTO:如何实现多场景 JSON 字段动态渲染

JsonView 单一 DTO&#xff1a;如何实现多场景 JSON 字段动态渲染 JsonView 单一 DTO&#xff1a;如何实现多场景 JSON 字段动态渲染1、JsonView 注解产生的背景2、为了满足不同场景下返回对应的属性的做法有哪些&#xff1f;2.1 最快速的实现则是针对不同场景新建不同的 DTO…

15 nginx 中默认的 proxy_buffering 导致基于 http 的流式响应存在 buffer, 以 4kb 一批次返回

前言 这也是最近碰到的一个问题 直连 流式 http 服务, 发现 流式响应正常, 0.1 秒接收到一个响应 但是 经过 nginx 代理一层之后, 就发现了 类似于缓冲的效果, 1秒接收到 10个响应 最终 调试 发现是 nginx 的 proxy_buffering 配置引起的 然后 更新 proxy_buffering 为…

安卓手机万能遥控器APP推荐

软件介绍 安卓手机也能当“家电总控台”&#xff1f;这款小米旗下的万能遥控器APP&#xff0c;直接把遥控器做成“傻瓜式操作”——不用配对&#xff0c;不连蓝牙&#xff0c;点开就能操控电视、空调、机顶盒&#xff0c;甚至其他品牌的电器&#xff01;雷总这波操作直接封神&…

PH热榜 | 2025-04-18

1. Wiza Monitor 标语&#xff1a;跟踪工作变动&#xff0c;接收Slack和电子邮件的提醒。 介绍&#xff1a;Wiza Monitor是一款用于追踪职位变动的工具&#xff0c;可以实时跟踪客户和潜在客户的工作变动&#xff0c;还可以通过电子邮件和Slack发送提醒&#xff0c;让你的客户…

Android平台 Hal AIDL 系列文章目录

目录 1. Android Hal AIDL 简介2. AIDL 语言简介3. Android 接口定义语言 (AIDL)4. 定义AIDL 接口5. AIDL 中如何传递 Parcelable 对象6. 如何使用AIDL 定义的远程接口进行跨进程通信7. 适用于 HAL 的 AIDL8. Android Hal AIDL 编译调试9. 高版本Android (AIDL HAL) 沿用HIDL方…

十、数据库day02--SQL语句01

文章目录 一、新建查询1.查询窗口的开启方法2. 单语句运行方法 二、数据库操作1.创建数据库2. 使用数据库3. 修改数据库4. 删除数据库和查看所有数据库5. 重点&#xff1a;数据库备份5.1 应用场景5.2 利用工具备份备份操作还原操作 5.3 扩展&#xff1a;使用命令备份 三、数据表…

实时直播弹幕系统设计

整个服务读多写少&#xff0c;读写比例大概几百比1. 如果实时性要求高的话&#xff0c;可以采用长连接模式&#xff08;轮询的话&#xff0c;时效性不好&#xff0c;同时对于评论少的直播间可能空转&#xff09; websocket 和 SSE架构 只要求服务端推送的话&#xff0c;可以…

[Java · 初窥门径] Java 语言初识

&#x1f31f; 想系统化学习 Java 编程&#xff1f;看看这个&#xff1a;[编程基础] Java 学习手册 0x01&#xff1a;Java 编程语言简介 Java 是一种高级计算机编程语言&#xff0c;它是由 Sun Microsystems 公司&#xff08;已被 Oracle 公司收购&#xff09;于 1995 年 5 …

【SQL Server】数据探查工具1.0研发可行性方案

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 想抢先解锁数据自由的宝子&#xff0c;速速戳我&#xff01;评论区蹲一波 “蹲蹲”&#xff0c;揪人唠唠你的超实用需求&#xff01; 【SQL Server】数据探查工具1.0研发可行性方案…

谓词——C++

1.一元谓词 1.定义 2.案例 查找容器有没有大于五的数字 #include<stdio.h> using namespace std; #include<string> #include<vector> #include<set> #include <iostream> class myfind { public:bool operator()(int a){return a > 5;} …

『前端样式分享』联系我们卡片式布局 自适应屏幕 hover动效 在wikijs中使用 (代码拿来即用)

目录 预览效果分析要点响应式网格布局卡片样式&#xff1a;阴影和过渡效果 代码优化希望 长短不一的邮箱地址在左右居中的同时,做到左侧文字对齐(wikijs可用)总结 欢迎关注 『前端布局样式』 专栏&#xff0c;持续更新中 欢迎关注 『前端布局样式』 专栏&#xff0c;持续更新中…

MySQL 缓存机制全解析:从磁盘 I/O 到性能优化

MySQL 缓存机制全解析&#xff1a;从磁盘 I/O 到性能优化 MySQL 的缓存机制是提升数据库性能的关键部分&#xff0c;它通过多级缓存减少磁盘 I/O 和计算开销&#xff0c;从而提高查询和写入的效率。 1. 为什么需要缓存&#xff1f; 数据库的性能瓶颈通常集中在磁盘 I/O 上。…

1.1 设置电脑开机自动用户登录exe开机自动启动

本文介绍两个事情&#xff1a; 1.Windows如何开机自动登录系统&#xff08;不用输密码) 2. 应用程序(.exe)如何开机自动启动 详细解释如下&#xff1a; 一、Windows如何开机自动登录系统&#xff08;不用输密码) 设备上的工控机&#xff0c;如果开机后都需要操作人员输入密码&…

基于 Python 和 OpenCV 技术的疲劳驾驶检测系统(2.0 全新升级,附源码)

大家好&#xff0c;我是徐师兄&#xff0c;一个有着7年大厂经验的程序员&#xff0c;也是一名热衷于分享干货的技术爱好者。平时我在 CSDN、掘金、华为云、阿里云和 InfoQ 等平台分享我的心得体会。 &#x1f345;文末获取源码联系&#x1f345; 2025年最全的计算机软件毕业设计…

OpenAI重返巅峰:o3与o4-mini引领AI推理新时代

引言 2025年4月16日&#xff0c;OpenAI发布了全新的o系列推理模型&#xff1a;o3和o4-mini&#xff0c;这两款模型被官方称为“迎今为止最智能、最强大的大语言模型&#xff08;LLM&#xff09;”。它们不仅在AI推理能力上实现了质的飞跃&#xff0c;更首次具备了全面的工具使…

Unity3d 6(6000.*.*)版本国区下载安装参考

前言 Unity3d 6.是最新的版本&#xff0c;是与来自世界各地的开发者合作构建、测试和优化的成果&#xff0c;现在可以完全投入生产&#xff0c;是我们迄今为止性能最出色、最稳定的 Unity 版本。Unity 6 有许多令人兴奋的新工具和功能&#xff1a;端到端多人游戏工作流程将加速…

第 3 期:逆过程建模与神经网络的作用(Reverse Process)

一、从正向扩散到逆向去噪&#xff1a;生成的本质 在上期中我们讲到&#xff0c;正向扩散是一个逐步加入噪声的过程&#xff0c;从原始图像 x_0到接近高斯分布的 x_T​&#xff1a; 而我们真正关心的&#xff0c;是从纯噪声中逐步还原原图的过程&#xff0c;也就是逆过程&…