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

set 认识及使用

序列式容器和关联式容器

之前学过的STL中string、vector、list、deque、array、forward_list等容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间⼀般没有紧密的关联关系,比如交换⼀下,他依旧是序列式容器。

关联式容器 与序列式容器不同的是 关联式容器逻辑结构通常是非线性结构 两个位置有紧密的关联关系 交换⼀下他的存储结构就被破坏了 关联式容器map/set  unordered_map/ unordered_set 

set

set其实就是上节二叉搜索树实现的key问题 不过底层是二叉搜索树优化后的红黑树 

第一个参数就是要里面存的类型  第二个参数就是之前的仿函数方式 默认支持小于比较 也就是左树都小于根节点的值 右树大于根节点值 第三个参数是空间配置器的内容 这里先不管

 第二第三个参数都有缺省值   一般情况下也只需要传第一个参数就可以满足我们的需求

set迭代器和之前的list一样是双向迭代器 支持++  --等的功能 所以需要用到++ --的一些算法set就是可以支持的

迭代器方式来打印是按照中序遍历的方式来进行的

如下 第二个个参数不传 迭代器打印默认为升序  当显示传第二个参数的为greater<int>时候 就按照逆序打印了

set里面不允许插入重复的数据  当插入的数据在set里面已经有了的话 重复的数据不会插进去 但是也不会报错 

所以我们使用set这个容器插入一些数据的时候    就会完成去重+升序排序的功能   另外set容器是不支持改的功能(因为底层的结构 改数据会破坏底层结构)

也支持在定义的时候再{}里面一下插入很多值

这是之前学习过的c+11的initializer_list 这也是一种模版类型 可以支持在创建时候在{}里面写值对它初始化   那么在insert里面写一个支持initializer_list类型的构造函数(和insert下面的第四个类型)后就可以支持这样插入了   

到时候传的{}里面的值会先隐式转换为initialiter_list 然后再拷贝构造传实参过去进行构造  这样的方式其实底层就是一个一个插数据 同样也不能插入重复的数据      这里的insert的返回值pair先不用管

也可以存string类型  会从第一位开始按照ASCII的方式比较

erase这里有三种方式 

先看第二种方式   删除掉一个值后会返回size_t类型 其实就是删除成功返回1删除失败(里面没有)返回0 那为什么不用bool类型呢 

这是为了和multiset统一 multisrt可以支持重复数据的插入删除查找 所以删除的时候删除一个值可以同时删除多个位置的值

第三种删除迭代器区间范围内的值后会返回此时传的第二个参数位置的迭代器

第一种方式就是删除一个迭代器位置的值 如下set是按照默认的方式是左树小右树大的方式  那么begin迭代器最左边节点就是最小值位置 那么用这种方式删除begin位置的值就是在删除了最小值

在创建对象的时候 模版第二个参数传greater<int>这样左树的值都大于根节点值 右树值都小于根节点的值 这样begin指向的位置就是最左边节点的最大值  删除begin位置的节点也就是删除了最大值

迭代器失效问题

这里的迭代器失效问题有两种 

上一篇学习了二叉搜索树的erase时候我们知道删除的方式有两种 1.如果删除节点只有一个孩子节点或者没有孩子节点的话会采用直接删除的方式(下图左)  2.如果有两个孩子节点 采取先用一个值和这个节点交换了 然后删除(下图右) 

 这两种情况都会导致迭代器失效 第二种虽然迭代器指向的节点没有释放但是迭代器的意义改变了 也算迭代器失效 对于vs下这两种情况都会直接报错 

stl中set的erase在删除后会返回下一个位置的迭代器 所以在使用之后可以让迭代器进行更新 

 

find会返回要找的值位置的迭代器 如果没有找到就会返回end位置的迭代器

如下 如果没有找到的话 最终会返回end位置迭代器打印没找到

它的查找是从根节点开始查找 判断一次之后就会到下一个节点 时间复杂度O(logN)

swap会直接交换两个set对象的根节点  clear就是把所有节点释放 emplace这里可以先看成和insert一样 比insert的效率更高

count会返回容器里面要找的值的个数 这里返回值为size_t 和erase第二个使用一样同样是要和multiset保持一致  

也可以用count来判断一个值是否存在  之前的find还需要接收返回的迭代器 然后判断是不是end count就可以直接通过返回值是不是1判断值存不存在

upper_bound 会返回大于val第一个位置的迭代器

lower_bound不是返回小于val第一个位置的迭代器  是返回大于等于val第一个位置的迭代器

那么为什么这么设置呢

如下 我们先插入了10 20 30 40 50 60 70 80 90然后我们想删除[30,50]范围内的值 对于左区间30我们用lower_bound会返回30位置的迭代器 itlow对于右区间50我们用upper_bounde会返回60位置的迭代器itup

而删除我们需要通过erase的第三个方式传迭代器区间的方式 对于第二个参数相当于end一样是删除位置的后一个位置 所以不会删除这个位置  这时候的itlow和itup刚好就是满足我们期望的

所以我们想删除哪个区间内的值只需要只需要让用lower_bound返回左区间的位置迭代器 用upper_bound返回右区间位置的迭代器 然后用erase传这两个迭代器就可以满足我们需求了     

set<int> s1 ;
for (int i = 1; i < 10; i++)s1.insert(i * 10); // 插入10 20 30 40 50 60 70 80 90for (auto e : s1)
{cout << e << " ";
}
cout << endl;
//要删除[30,50] 范围内的值
auto itlow = s1.lower_bound(30);  // 返回 >= 30的迭代器也就是30这个位置的迭代器
auto itup = s1.upper_bound(50);  // 返回 > 50的迭代器  也就是60位置的迭代器
s1.erase(itlow, itup);
for (auto e : s1)
{cout << e << " ";
}
cout << endl;

multiset

multiset和set的区别就是可以支持重复数据的增删插

基本的功能和set都差不多  count会返回这个值的个数   

在删除和查找上有些差异 有多个相同数的话 find会找中序遍历的第一个数  比如里面有很多的5 在找到5之后会继续判断此时位置的左树里面有没有5了  直到找到一个此时位置的左树里面没有5了 此时的位置才是find要找的

我们知道迭代器是按照中序遍历的方式  找到中序遍历的第一个有助于继续++遍历 如下找到5后迭代器更新可以继续到下一个位置一直把所有5都删掉

当然要删除里面的一个值不需要这么麻烦 直接erase(x)就会把里面所有x的值都删掉



文章转载自:

http://pXKNAgAy.znsyn.cn
http://sDXqbyzf.znsyn.cn
http://uh6KxLzV.znsyn.cn
http://njNbzOh0.znsyn.cn
http://zrA50k7h.znsyn.cn
http://Uv4VvYvg.znsyn.cn
http://onE0L7PD.znsyn.cn
http://rfc2ii1a.znsyn.cn
http://UwN41HjW.znsyn.cn
http://w9bYjyKF.znsyn.cn
http://DBc5bZvk.znsyn.cn
http://ql78YNmg.znsyn.cn
http://v6CKf12X.znsyn.cn
http://Z79ZhGYz.znsyn.cn
http://uV53uDby.znsyn.cn
http://1JyO36dp.znsyn.cn
http://dZsHhWPV.znsyn.cn
http://3KcHsJJx.znsyn.cn
http://eDEVa5le.znsyn.cn
http://HiqWG98T.znsyn.cn
http://4gcSxtx7.znsyn.cn
http://7pZsL3Cf.znsyn.cn
http://YDxuEB3Y.znsyn.cn
http://Y5TVRVcA.znsyn.cn
http://dB0YowQ5.znsyn.cn
http://2RGuCI4C.znsyn.cn
http://bjqt2eJm.znsyn.cn
http://N1KWLgLU.znsyn.cn
http://RfAgMAdX.znsyn.cn
http://3r46pXR5.znsyn.cn
http://www.dtcms.com/a/378585.html

相关文章:

  • 如何打造“高效、安全、精准、可持续”的智能化实验室?
  • 究竟什么时候用shared_ptr,什么时候用unique_ptr?
  • 前端抽象化,打破框架枷锁:react现代化项目中的思想体现
  • 基于开源AI智能名片、链动2+1模式与S2B2C商城小程序的流量运营与个人IP构建研究
  • gstreamer:创建组件、管道和总线,实现简单的播放器(Makefile,代码测试通过)
  • Kibana 双栈网络(Dual-Stack)支持能力评估
  • go 日志的分装和使用 Zap + lumberjack
  • 河北智算中心绿色能源占比多少?
  • 在能源互联网时代天硕工业级SSD固态硬盘为何更受青睐?
  • 关于rust的crates.io
  • 使用Rust实现服务配置/注册中心
  • C++ 类与对象(下):从构造函数到编译器优化深度解析
  • DNS 域名解析
  • EasyDSS重装系统后启动失败?解决RTMP推流平台EasyDss服务启动失败的详细步骤
  • 自动驾驶中的传感器技术45——Radar(6)
  • 第四章 Elasticsearch索引管理与查询优化
  • 拆分了解HashMap的数据结构
  • Sqlite“无法加载 DLL“e_sqlite3”: 找不到指定的模块”解决方法
  • 项目 PPT 卡壳?模型效果 + 训练数据展示模块直接填 ,451ppt.vip预制PPT也香
  • react-native项目通过华为OBS预签名url实现前端直传
  • Linux-> UDP 编程1
  • Pytest+requests进行接口自动化测试2.0(yaml)
  • 【容器使用】如何使用 docker 和 tar 命令来操作容器镜像
  • 科普:在Windows个人电脑上使用Docker的极简指南
  • 【面试场景题】电商订单系统分库分表方案设计
  • 微服务保护全攻略:从雪崩到 Sentinel 实战
  • springcloud二-Sentinel
  • Redis 持久化与高可用实践(RDB / AOF / Sentinel / Cluster 全解析)
  • Semaphore 信号量深度解析
  • 门店网络重构:告别“打补丁”,用“云网融合”重塑数字竞争力!