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

【C++】set详解

📢博客主页:https://blog.csdn.net/2301_779549673
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨

在这里插入图片描述

在这里插入图片描述

文章目录

  • 📢前言
  • 🏳️‍🌈 一、set类的介绍
  • 🏳️‍🌈二、set的构造和迭代器
  • 🏳️‍🌈三、set的增删查
  • 🏳️‍🌈四、insert和迭代器遍历使用样例
  • 👥总结


📢前言

Set 是 C++ 标准模板库(STL)中的一种关联容器,主要用于存储不重复且有序的元素。其内部实现采用红黑树,这种数据结构具有自动排序的特性,能够高效地进行插入、删除和查找操作。

红黑树是一种平衡二叉搜索树,它的统计性能优于一般的平衡二叉树。在 set 中,每个元素的值都唯一,并且元素的值不能直接被改变。这是因为 set 中的元素值就是其键值,关系到 set 元素的排列规则。如果任意改变 set 的元素值,会严重破坏 set 的组织。

Set 的迭代器被定义为底层红黑树的 const_iterator,杜绝了写入操作。这意味着我们不能通过 set 的迭代器直接修改元素的值。例如,当我们尝试通过 set 的迭代器改变元素的值时,编译器会报错。

此外,当对 set 进行元素新增操作(insert)或删除操作(erase)时,操作之前的所有迭代器,在操作完成之后都依然有效,被删除的那个元素的迭代器必然是个例外。这种特性使得 set 在进行动态操作时,能够保持迭代器的有效性,方便了程序的编写和维护。

总的来说,C++ 中的 set 容器以其独特的特性和高效的内部实现,为程序员提供了一种方便、可靠的数据存储和操作方式。


🏳️‍🌈 一、set类的介绍

  • set的声明如下,T就是set底层关键字的类型.
  • set默认要求T支持小于比较,如果不支持或者想按自己的需求走可以自行实现仿函数传给第二个模版参数
  • set底层存储数据的内存是从空间配置器申请的,如果需要可以自己实现内存池,传给第三个参数。
  • 一般情况下,我们都不需要传后两个模版参数。
  • set底层是用红黑树实现,增删查效率是O(l0gN),迭代器遍历是走的搜索树的中序,所以是有序的。
  • 前面部分我们已经学习了vector/list等容器的使用,STL容器接口设计,高度相似,所以这里我们就不再一个接口一个接口的介绍,而是直接带着大家看文档,挑比较重要的接口进行介绍。
template < class T, // set::key_type/value_typeclass Compare = less<T>, // set::key_compare/value_compareclass Alloc = allocator<T> // set::allocator_type> class set;

🏳️‍🌈二、set的构造和迭代器

  • set的构造我们关注以下几个接口即可。
  • set的支持正向和反向迭代遍历,遍历默认按升序顺序,因为底层是二叉搜索树,迭代器遍历走的中序;支持迭代器就意味着支持范围for,set的iterator和const iterator都不支持迭代器修改数据,修改关键字数据,破坏了底层搜索树的结构。

Set 的构造方式主要有以下几种:
默认构造函数:set st;,创建一个空的 set。例如:set mySet;。
拷贝构造函数:set(const set &st);,创建一个新的 set,它是现有 set 的副本。例如:set mySet = {1, 2, 3}; set anotherSet(mySet);。
使用区间构造:可以用一个已有的区间中的元素构造 set,如set s2(s1.begin(), s1.end());。
赋值操作可以使用重载的等号操作符:set& operator=(const set &st);,将一个 set 的内容赋值给另一个已经存在的 set。例如:set mySet = {1, 2, 3}; set anotherSet; anotherSet = mySet;。

// empty (1) ⽆参默认构造
explicit set (const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
// range (2) 迭代器区间构造
template <class InputIterator>
set (InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& = allocator_type());
// copy (3) 拷⻉构造
set (const set& x);
// initializer list (5) initializer 列表构造
set (initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
// 迭代器是⼀个双向迭代器
iterator -> a bidirectional iterator to const value_type
// 正向迭代器
iterator begin();
iterator end();
// 反向迭代器
reverse_iterator rbegin();
reverse_iterator rend();

🏳️‍🌈三、set的增删查

set的增删查关注以下几个接口即可:

  • 插入元素
    使用insert方法可以在 set 中插入元素。例如:mySet.insert(5);。如果元素已存在,插入操作将被忽略。insert方法的返回值是个pair结构的对组,pair<iterator, bool>,bool 代表插入是否成功。当向 set 容器添加元素成功时,该迭代器指向 set 容器新添加的元素,bool 类型的值为 true;如果添加失败,即证明原 set 容器中已存有相同的元素,此时返回的迭代器就指向容器中相同的此元素,同时 bool 类型的值为 false。
  • 查找元素
    使用find方法查找 set 中元素。例如:auto it = mySet.find(element);,如果找到元素,it将指向该元素;否则,it将指向 set 的尾后。可以通过判断it是否等于end()来确定元素是否被找到。
  • 删除元素
    使用erase方法删除 set 中元素,有以下几种方式:
    删除迭代器指向的元素:erase(pos);,例如:auto it = mySet.find(3); if(it!= mySet.end()){ it = mySet.erase(it); }。
    删除指定值的元素:erase(elem);,例如:mySet.erase(4);。
    删除区间内的元素:erase(beg, end);。
  • 其他方法
    size():返回 set 中元素的数目。
    empty():判断 set 是否为空。如果为空,返回 true;否则返回 false。
    clear():清空 set 中的所有元素。
    lower_bound():返回大于或等于给定元素的第一个元素的迭代器。
    upper_bound():返回大于给定元素的第一个元素的迭代器。
    equal_range():返回一组迭代器,表示给定元素在 set 中的范围。
Member types
key_type -> The first template parameter (T)
value_type -> The first template parameter (T)
// 单个数据插⼊,如果已经存在则插⼊失败
pair<iterator, bool> insert (const value_type& val);
// 列表插⼊,已经在容器中存在的值不会插⼊
void insert (initializer_list<value_type> il);
// 迭代器区间插⼊,已经在容器中存在的值不会插⼊
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
// 查找val,返回val所在的迭代器,没有找到返回end()
iterator find (const value_type& val);
// 查找val,返回Val的个数
size_type count (const value_type& val) const;
// 删除⼀个迭代器位置的值
iterator erase (const_iterator position);
// 删除val,val不存在返回0,存在返回1
size_type erase (const value_type& val);
// 删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);
// 返回⼤于等val位置的迭代器
iterator lower_bound (const value_type& val) const;
// 返回⼤于val位置的迭代器
iterator upper_bound (const value_type& val) const;

易错点提示
end()函数的正确用法:end()函数的作用不是用于返回最后一个元素,而是用于返回 set 中最后一个元素的后一个位置的指针。如果一个 set 中的元素是<1,2,3>,那么返回的就是元素 3 之后的一位的指针。如果要看最后一个元素,可以使用遍历的方式找到最后一个元素,或者使用其他方法。

不能直接 copy:不能将一个 set 直接使用=号赋值给另外一个 set。如下面的写法就是错误的:set set1; set set2 = set1;。这种写法会导致编译错误或者不可预期的结果。在 C++ 中,set 的赋值操作需要使用特定的方法,如拷贝构造函数或者赋值运算符重载。

🏳️‍🌈四、insert和迭代器遍历使用样例

#include<iostream>
#include<set>
using namespace std;
int main() {
// 去重+升序排序set<int> s;
// 去重+降序排序(给⼀个⼤于的仿函数)
//set<int, greater<int>> s;s.insert(5);s.insert(2);s.insert(7);s.insert(5);
//set<int>::iterator it = s.begin();auto it = s.begin();while (it != s.end()) {// error C3892: “it”: 不能给常量赋值
// *it = 1;cout << *it << " ";++it;}cout << endl;
// 插⼊⼀段initializer_list列表值,已经存在的值插⼊失败s.insert({ 2, 8, 3, 9 });for (auto e : s) {cout << e << " ";}cout << endl;set<string> strset = { "sort", "insert", "add" };
// 遍历string⽐较ascll码⼤⼩顺序遍历的for (auto& e : strset) {cout << e << " ";}cout << endl;
}

👥总结


本篇博文对 set 做了一个较为详细的介绍,不知道对你有没有帮助呢

觉得博主写得还不错的三连支持下吧!会继续努力的~

请添加图片描述

相关文章:

  • 如何选择合适的跨境网络专线?
  • #git 问题failed to resolve head as a valid ref
  • RabbitMQ 实验入门
  • 【Ubuntu】DNS设置不生效/重启被重置
  • TypeSctipt学习第二篇
  • uni-app之旅-day01-home页
  • 第18周 3-过滤器
  • 关于公司小程序项目在登录流程获取token并全局使用的梳理(学习篇)
  • 【从零开始实现stm32无刷电机FOC】【实践】【7.1/7 硬件设计】
  • 25 基于51单片机的温度电流电压检测系统(压力、电压、温度、电流、LCD1602)
  • MongoDB入门
  • 第十三届蓝桥杯真题Python c组D.数位排序(持续更新)
  • A Learning-Based Approach to Static Program Slicing —— 论文笔记
  • web应用合规(一)双因子认证2FA解决方案
  • 音视频通话 SDK
  • JavaScript-如何实现克隆(clone)函数
  • angular组件开发
  • ES6核心特性
  • GraphQL学习过程应该是这样的
  • js继承的实现方法
  • QQ浏览器x5内核的兼容性问题
  • Spring Cloud Feign的两种使用姿势
  • 每天10道Java面试题,跟我走,offer有!
  • 模型微调
  • 排序(1):冒泡排序
  • 使用权重正则化较少模型过拟合
  • 小试R空间处理新库sf
  • C# - 为值类型重定义相等性
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 如何用纯 CSS 创作一个货车 loader
  • ​iOS实时查看App运行日志
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • #android不同版本废弃api,新api。
  • #define 用法
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (MATLAB)第五章-矩阵运算
  • (补充)IDEA项目结构
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (简单) HDU 2612 Find a way,BFS。
  • (三)uboot源码分析
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (数据结构)顺序表的定义
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • .NET 8 跨平台高性能边缘采集网关
  • .Net 中Partitioner static与dynamic的性能对比
  • .skip() 和 .only() 的使用
  • .so文件(linux系统)
  • /boot 内存空间不够
  • @ConditionalOnProperty注解使用说明
  • [ Linux Audio 篇 ] 音频开发入门基础知识
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149
  • [20140403]查询是否产生日志
  • [AutoSar]状态管理(五)Dcm与BswM、EcuM的复位实现