【C++历险记】STL之set详解

个人主页:兜里有颗棉花糖💪
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【C++之路】💌
本专栏旨在记录C++的学习路线,望对大家有所帮助🙇‍
希望我们一起努力、成长,共同进步。🍓
在这里插入图片描述

目录

  • set
    • Modifiers
      • insert(插入数据)
      • erase(删除元素)
    • Operations:
      • find(查找数据)
      • count
        • find函数和count函数的区别
      • lower_bound & upper_bound
    • 补充(multiset)
      • equal_range

set

集合(Set):是一种不允许重复元素的容器,它的元素是按照某种特定顺序组织的。

头文件:

  • #include<set>

迭代器访问:

// 方式1:
set<int>::iterator it = s.begin();
while (it != s.end())
{
	cout << *it << ' ';
	it++;
}
// 方式2
for (auto e : s)
	cout << e << ' ';
// 方式3
for (set<int>::iterator it1 = s.begin(); it1 != s.end(); it1++)
	cout << *it1 << ' ';
// 其实这里方式1和方式3是等同的

Modifiers

insert(插入数据)

void test_set1()
{
	set<int> s;
	s.insert(1);
	s.insert(2);
	s.insert(3);
	s.insert(4);
	s.insert(4);
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << ' ';
		it++;
	}
	cout << endl;
}

运行结果如下:
在这里插入图片描述
可以看到结果中并没有打印两个4,因为set容器会对其中的元素进行去重操作。

erase(删除元素)

void test_set2()
{
	set<int> s;
	s.insert(1);
	s.insert(2);
	s.insert(3);
	s.insert(4);
	s.insert(4);
	set<int>::iterator it = s.begin();
	for (auto e : s)
		cout << e << ' ';
	cout << endl;
	// 删除元素方式1
	auto pos = s.find(3);
	s.erase(pos);
	//s.erase(3); // 删除元素方式2
	for (auto e : s)
		cout << e << ' ';
	cout << endl;
}

运行结果如下:
在这里插入图片描述

上面提供了两种删除元素的方式,我们要根据不同的场景来选择不同的方式来进行删除元素。

Operations:

find(查找数据)

set的find函数用于在set中查找指定的元素,如果找到了,它返回指向该元素的迭代器;如果没有找到,返回一个指向set末尾元素的迭代器
在这里插入图片描述

请看举例:

void test_set3()
{
	set<int> s;
	s.insert(1);
	s.insert(2);
	s.insert(3);
	s.insert(4);
	s.insert(4);
	auto pos1 = s.find(5);
	auto pos2 = s.find(4);
	if (pos1 != s.end())
		s.erase(pos1);
	else
		cout << "没找到该元素" << endl;
	if (pos2 != s.end())
		s.erase(pos2);
	for (auto e : s)
		cout << e << ' ';
}

运行结果如下:

在这里插入图片描述
需要注意的是,set的find函数和库中的find函数是不同的函数。

区别主要是查找速度上,set的find函数查找元素的时间复杂度是O(logN)

而库中的find函数查找的速度是O(N)

所以日常当中如果我们需要使用set中的find函数来查找元素时,我们可以这样使用,请看:

set<int> s;
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(4);
s.insert(4);
if (s.find(4) != s.end())
	cout << "该元素已被找到" << endl;
else
	cout << "未找到该元素" << endl;

count

在这里插入图片描述
如果该元素存在的话则返回1,否则返回0。

这里只举一个简单的例子即可,请看:

set<int> s;
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(4);
s.insert(4);
if (s.count(4))
	cout << "集合中存在该元素" << endl;
else
	cout << "集合中不存在该元素" << endl;

运行结果如下:
在这里插入图片描述

find函数和count函数的区别

set的find函数和count函数都是用来查找集合元素的函数,但要说区别的话还是有的。

返回值:find函数返回一个指向集合元素的迭代器,如果集合中不存在该元素,则迭代器指向集合的末尾;而count函数则返回集合中值等于给定值的元素数量,因为集合中元素是唯一的,所以返回值只能是0或1。

时间复杂度:count函数的时间复杂度要比find函数快,因为count函数只需要确定是否存在该元素,而不必遍历整个集合。

如果只需要知道一个元素是否存在于集合中,可以使用count函数;如果需要获取该元素的迭代器,或者对集合进行修改、删除、插入等操作,就需要使用find函数。

lower_bound & upper_bound

lower_bound函数用于查找大于或等于指定元素的第一个元素的迭代器如果找到指定元素,则返回指向该元素的迭代器,否则返回指向set末尾(即end)的迭代器。

upper_bound函数用于查找大于指定元素的第一个元素的迭代器;如果没有找到则返回指向set末尾(即end)的迭代器。

请看举例:

void test_set5()
{
	set<int> s;
	for (int i = 1; i <= 10; i++) s.insert(i * 10); // 10 20 30 40 50 60 70 80 90 100

	set<int>::iterator itlow, itup;
	itlow = s.lower_bound(30), itup = s.upper_bound(60);
	cout << *itlow << ' ' << *itup << endl;
	s.erase(itlow, itup);
	for (auto e : s) cout << e << ' ';
	cout << endl;
}

运行结果如下:
在这里插入图片描述

这里我们需要注意的是,erase函数删除的范围是左闭右开的,即实际删除的元素包括第一个迭代器指向的元素,但不包括第二个迭代器指向的元素。
同时这里要再次强调lower_bound函数查找的是大于或等于指定元素的第一个元素的迭代器,而upper_bound用于查找大于指定元素的第一个元素的迭代器。

补充(multiset)

这里要补充一点,在C++中setmultiset是C++标准库中的两个关联容器,二者的唯一区别在于容器中的元素是否唯一

这里举一个简单的例子即可,请看:

void test_set6()
{
	multiset<int> s;
	s.insert(1);
	s.insert(2);
	s.insert(4);
	s.insert(5);
	s.insert(5);
	s.insert(5);
	s.insert(3);
	s.insert(6);
	for (auto e : s) cout << e << ' ';
	cout << endl;
	cout << "容器中元素5的个数是:" << s.count(5) << endl;
	
	auto ret = s.equal_range(5);
	auto itlow = ret.first;
	auto itup = ret.second;
	s.erase(itlow, itup);
	for (auto e : s) cout << e << ' ';
	cout << endl;
}

运行结果如下:
在这里插入图片描述

这里我们要注意的是,如果multiset容器中有多个元素5,那么,如果使用find函数来查找元素5的话,此时应该返回的是中序的第一个元素5。请看举例:

multiset<int> s;
s.insert(1);
s.insert(2);
s.insert(4);
s.insert(5);
s.insert(5);
s.insert(5);
s.insert(3);
s.insert(6);
for (auto e : s) cout << e << ' ';
cout << endl;
auto pos = s.find(5);
while (pos != s.end())
{
	cout << *pos << ' ';
	pos++;
}
cout << endl;

运行结果如下:
在这里插入图片描述

equal_range

我们其实可以认为count函数和equal_range函数就是专门为multiset容器设计的。因为set容器中不存在相等的值,而multiset容器才存在相等的值。

下面我们来看一下multiset容器是如何使用equal_range函数的。

方式1:

void test_multiset1()
{
	multiset<int> s;
	s.insert(1);
	s.insert(2);
	s.insert(4);
	s.insert(5);
	s.insert(5);
	s.insert(5);
	s.insert(3);
	s.insert(6);
	for (auto e : s) cout << e << ' ';
	cout << endl;
	auto ret = s.equal_range(5);
	auto itlow = ret.first;
	auto itup = ret.second;

	s.erase(itlow, itup);
	for (auto e : s) cout << e << ' ';
	cout << endl;
}

在这里插入图片描述

方式2:
在这里插入图片描述
这里注意itlow和itup迭代器指向的值。

错误演示1:
在这里插入图片描述

这里equal_range返回的是一个不存在的区间。所以最终肯定会报错。

错误演示2:

在这里插入图片描述
这里出错点就在于返回给itup的值是一个不合法的值,所以*itup的时候就会报错。

以上就是对set容器用法的介绍,本文就到这里吧,再见啦友友们!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/145357.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++中关于多线程并发访问实例函数与静态函数

问题 1 C中多个线程共同执行一个实例函数&#xff0c;该函数是在线程的栈空间吗&#xff1f;对于函数中的多线程共享变量又是存储在哪里呢&#xff1f; example: 在该例子中线程绑定当前对象(this)的实例函数captureVideo, 并将int参数传递过去。但是对于captureVideo中多个线…

双写绕过 [极客大挑战 2019]BabySQL 1

打开题目 随便输入账号密码 根据报错信息可知这是单引号的字符型注入 那我们试试万能密码 1 or 11 页面报错 1 or 11 页面报错 而且根据报错内容显示是没有我们注入上去的or的 那我们就试试 1 order by 3 # 页面报错&#xff0c;根据报错显示页面过滤掉了or和by 那我们…

酷柚易汛ERP-购货订单操作指南

1、应用场景 先下购货订单&#xff0c;收货入库后生成购货单。 2、主要操作 2.1 新增购货订单 打开【购货】-【购货订单】新增购货订单。&#xff08;*为必填项&#xff0c;其他为选填&#xff09; ① 录入供应商&#xff1a;点击供应商字段框的 &#xff0c;在弹框中选择供…

新版本Idea设置启动参数

1.进入配置页面 2.点击下图红框的部分&#xff0c;会看到有很多操作可选 3.选择添加VM参数即可 此时就会多出一个可以输入参数的框了&#xff0c;如下&#xff1a;

第 1 章 概述 习题

1-1 因特网的前身是 1969 年创建的第一个分组交换网&#xff08;&#xff09;。 A. internet B. Internet C. NSFNET D. ARPANET 【答案】 D 【解析】 1-2 因特网上的数据交换方式是&#xff08;&#xff09;。 A. 电路交换 B. 报文交换 C. 分组交换 D. 光交换 【答…

springcloud旅游网站源码

开发技术&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;idea&#xff0c;nodejs&#xff0c;vscode springcloud springboot mybatis vue 功能介绍&#xff1a; 用户端&#xff1a; 登录注册 首页显示搜索景区&#xff0c;轮播图&#xff0c;旅游攻略列表 点击攻…

计算机毕业设计选题推荐-体育赛事微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

echarts 地图点位图标为动图,且可以多个不同图标

根据项目需求,echarts地图点位图标要是动图,且可以设置不同图标,经过多方查找,找到解决方案,可以用svg使gif动起来 let myChartChina echarts.init(document.getElementById("myChartChina"), "transparent", {renderer: "svg"});其中transpare…

线程池参数该怎么配置?这可能是为数不多的好答案

前言 CPU 密集型 CPU 核数 1 IO 密集型 CPU 核数 * 2 相信这个公式可谓是线程池八股文中老生常谈的万能公式了&#xff0c;但现实却很骨感&#xff0c;我之前有个系统就是按照这个公式算出来的参数去配置的。结果效果并不好&#xff0c;甚至让下游系统直呼受不了。这个东西…

阶段七-Day01-SpringMVC

一、Sping MVC的介绍 1. 使用Front(前端)设计模式改写代码 1.1 目前我们的写法 目前我们所写的项目&#xff0c;持久层、业务层的类都放入到Spring容器之中了。他们之间需要注入非常方便&#xff0c;只需要通过Autowired注解即可。 但是由于Servlet整个生命周期都是被Tomca…

并查集详解(附例题和模板)

一、并查集 &#xff08;1&#xff09;处理问题的类型 1.将两个集合合并 2.询问两个元素是否在一个集合当中 询问 1.fa[x]a; 2.if(fa[x]fa[y]) o(1) 在o(1)的复杂度内进行两个操作 &#xff08;2&#xff09;基本原理 基本原理&#xff1a;每个集合用一棵树来表示&#…

振南技术干货集:深入浅出的Bootloader(5)

注解目录 1、烧录方式的更新迭代 1.1 古老的烧录方式 (怀旧一下&#xff0c;单片机高压烧录器。) 1.2 ISP 与ICP 烧录方式 (还记得当年我们玩过的 AT89S51?) 1.3 更方便的 ISP 烧录方式 1.3.1串口 ISP &#xff08;是 STC 单片机成就了我们&#xff0c;还是我们成就了…

破解tomcat密码并上传webshell

tomcat基础认证爆破 暴力破解 进入vulnhub的tomcat8目录&#xff0c;启动环境 由于tomcat密码默认最大尝试错误次数为5次&#xff0c;需要修改server.xml&#xff0c;修改下面字段 failureCount"10000000000" lockOutTime"0"tomcat默认界面&#xff0c;…

一个破单机,也要用远程缓存?

大家好&#xff0c;豆小匠终于开始Coding了&#xff0c;这期来聊聊实战相关的杂谈。 正文开始&#xff01; 作为编程萌新的时候&#xff0c;总想着把程序做复杂&#xff0c;堆技术栈。 但是程序是为场景服务的&#xff0c;比如&#xff0c;我想提高接口的响应速度&#xff0c…

传输层协议-UDP协议

目录 传输层再谈端口号端口号范围划分认识知名端口号 UDP协议UDP协议格式UDP数据封装UDP数据分用 UDP协议的特点面向数据报 UDP缓冲区UDP使用注意事项基于UDP的应用层协议 传输层 实际上我们应用层的数据并不是直接发给网络的&#xff0c;而是需要先将数据发送给传输层&#xf…

客户下单时如何自动匹配到最近的门店

有些商家有多个门店&#xff0c;当客户下单时&#xff0c;希望能够将客户下的订单分配给最近的门店。下面就具体介绍一下在采云小程中是如何实现的。 首先&#xff0c;为了简便起见&#xff0c;请确定门店高级设置保持着默认设定。因为单独的商品管理模式以及独享的商品信息模…

一篇博客读懂队列——Queue

目录 一、队列的概念和结构 ​二、队列的实现 2.1队列的初始化QueueInit 2.2队列的摧毁QueueDestroy 2.3插入结点QueuePush 2.4删除结点QueuePop 2.5返回队头QueueFront 2.6返回队尾QueueBack 2.7判断队列为空QueueEmpty 2.8统计队列数目QueueSize 一、队列的概念和…

Vue computed 计算属性

1.计算属性的相关知识 概念 &#xff1a;基于现有的数据&#xff0c;计算出来的新属性。依赖数据的变化&#xff0c;自动重新计算。 语法&#xff1a; ① 声明在 computed 配置项 中&#xff0c;一个计算属性对应一个函数 ② 使用起来和普通属性一样使用 {{ 计算属性名 …

Vue3+Element Plus表格多字段组合排序方法

一、问题描述 默认el-table是单个字段排序的&#xff0c;点击表格头排序&#xff0c;老排序字段的排序箭头样式并没有保留&#xff0c;仅仅保留了新点击字段的样式。 二、实现效果 选择多列组合排序时可以高亮多列箭头。 三、解决方法 3.1 如何记录多个字段被选择&#xff…