C++ —— set系列的使用

news2024/11/26 14:58:21

目录

1. 序列式容器和关联式容器

2. set和multiset参考⽂档 

3. set类的介绍

4. set的构造和迭代器

4.1 set的增删查 

4.1.1 插入     

4.1.2 查找

4.1.3 删除

5. multiset和set的差异 


1. 序列式容器和关联式容器

前⾯我们已经接触过STL中的部分容器如:string、vector、list、deque、array

forward_list等,这些容器统称为序列式容器

   

因为逻辑结构为线性序列的数据结构,两个位置存储的值之间⼀般没有紧密的关联关系,⽐如交换⼀下,他依旧是序列式容器。顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的


关联式容器也是⽤来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是⾮线性结构,两个位置有紧密的关联关系,交换⼀下,他的存储结构就被破坏了。顺序容器中的元素是按关键字来保存和访问的

     

关联式容器有map/set系列unordered_map/unordered_set(哈希表)系列


map和set底层是红⿊树,红⿊树是⼀颗平衡⼆叉搜索树。set是key搜索场景的结构,map是key/value搜索场景的结构


2. set和multiset参考⽂档 

- C++ Referenceicon-default.png?t=O83Ahttps://legacy.cplusplus.com/reference/set/


3. set类的介绍

   
1. set的声明如下,T就是set底层关键字的类型,set是去重的

   
2. set默认要求T⽀持⼩于⽐较,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现仿函数传给第⼆个模版参数

   
3. set底层存储数据的内存是从空间配置器申请的,如果需要可以⾃⼰实现内存池,传给第三个参数

   
4.  ⼀般情况下,我们都不需要传后两个模版参数

    
5. set底层是⽤红⿊树实现,增删查效率是 O(logN) ,迭代器遍历是⾛的搜索树的中序,所以是有序的 

template < class T,                 // set::key_type/value_type
                   
class Compare = less<T>,            // set::key_compare/value_compare

class Alloc = allocator<T>          // set::allocator_type

> class set;

 


4. set的构造和迭代器

set的⽀持正向和反向迭代遍历,遍历默认按升序顺序,因为底层是⼆叉搜索树,迭代器遍历⾛的中序;⽀持迭代器就意味着⽀持范围for

     

set的iterator和const_iterator都不⽀持迭代器修改数据,修改关键字数据,破坏了底层搜索树的结构

 set的构造我们关注以下⼏个接口即可

// 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();

4.1 set的增删查 

4.1.1 插入     

set容器在插入后默认是升序存储的,并且无法插入重复的元素,但是可以使用仿函数来传参实现降序,也可以插入一段元素,通常使用ASCII码来进行比较大小

插入接口 :

// 单个数据插⼊,如果已经存在则插⼊失败 
pair<iterator,bool> insert (const value_type& val);

// 列表插⼊,已经在容器中存在的值不会插⼊ 
void insert (initializer_list<value_type> il);

// 迭代器区间插⼊,已经在容器中存在的值不会插⼊ 
template <class InputIterator>
void insert (InputIterator first, InputIterator last);

 

使用 :

//插入
int main()
{
	//去重+默认升序排列
	set<int> s1;
	s1.insert(2);
	s1.insert(4);
	s1.insert(3);
	s1.insert(2);
	s1.insert(5);
	s1.insert(9);
	//迭代器遍历
	//set<int, greater<int>>::iterator it = s1.begin();
	auto it_s1 = s1.begin();
	while (it_s1 != s1.end())
	{
		//*it = 1;---->error
		//不可以修改
		cout << *it_s1 << " ";
		++it_s1;
	}
	cout << endl;
 
	//去重+使用仿函数降序排列
	set<int,greater<int>> s2;
	s2.insert(2);
	s2.insert(4);
	s2.insert(3);
	s2.insert(2);
	s2.insert(5);
	s2.insert(9);
	//迭代器遍历
	//set<int, greater<int>>::iterator it = s2.begin();
	auto it_s2 = s2.begin();
	while (it_s2 != s2.end())
	{
		cout << *it_s2 << " ";
		++it_s2;
	}
	cout << endl;
 
	//插⼊⼀段initializer_list列表值,已经存在的值插⼊失败
	set<int> s3;
	s3.insert({ 2,3,4,5,5,7,9,11 });
	for (auto e : s3)
	{
		cout << e << " ";
	}
	cout << endl;
 
	//插入string类,通过ASCII码的大小来排序
	set<string> s4;
	s4.insert({ "zhangsan", "lisi", "wangwu" });
	for (auto e : s4)
	{
		cout << e << " ";
	}
	cout << endl;
 
 
	return 0;
}

 


4.1.2 查找

在算法库中的find使用的是遍历查找,时间复杂度是O(N)

set自身的find是符合平衡二叉树的查找,时间复杂度O(logN)

// 算法库的查找 O(N) 
 auto pos1 = find(s.begin(), s.end(), x); 

 // set⾃⾝实现的查找 O(logN) 
 auto pos2 = s.find(x); 

 查找接口

// 查找val,返回val所在的迭代器,没有找到返回end() 
iterator find (const value_type& val);

// 查找val,返回Val的个数 
size_type count (const value_type& val) const;

使用 :

1. find接口直接查找

int main()
{
	//去重+默认升序排列
	set<int> s;
	s.insert(2);
	s.insert(4);
	s.insert(3);
	s.insert(2);
	s.insert(5);
	s.insert(9);
	//迭代器遍历
	//set<int, greater<int>>::iterator it = s.begin();
	auto it = s.begin();
	while (it != s.end())
	{
		//*it = 1;---->error
		//不可以修改
		cout << *it << " ";
		++it;
	}
	cout << endl;
 
	int x = 0;
	cout << "请输入你要查找的数字:";
	cin >> x;
	//如果查找不到就会返回迭代器的尾部
	/*auto pos = s.find(x);
	if (pos != s.end())
	{
		cout << x << "存在" << endl;
	}
	else
	{
		cout << x << "不存在" << endl;
	}*/
 
	return 0;
}

count函数间接查找 

//使用count来间接查找
	//count可以统计元素出现的次数,如果出现0次就不存在,反之则存在
 
	if (s.count(x))
	{
		cout << x << "存在" << endl;
	}
	else
	{
		cout << x << "不存在" << endl;
	}

 


4.1.3 删除

删除接口:

// 删除⼀个迭代器位置的值 
iterator erase (const_iterator position);

// 删除val,val不存在返回0,存在返回1 
size_type erase (const value_type& val);

// 删除⼀段迭代器区间的值 
iterator erase (const_iterator first, const_iterator last);

有关查找区间的迭代器:

    

迭代器区间通常都是左闭右开的一个范围区间,也就说[a,b)的一个类型,这里lower_bound与upper_bound可以实现查找一个左闭右开的区间以供操作 

// 返回⼤于等val位置的迭代器 
iterator lower_bound (const value_type& val) const;

// 返回⼤于val位置的迭代器 
iterator upper_bound (const value_type& val) const;

使用 :

直接删除并判断是否删除成功 

//删除
int main()
{
	set<int> s;
	s.insert({ 2,4,5,2,6,8,10,15 });
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
 
	//删除最小的元素就删除排序后的首元素
	s.erase(s.begin());
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
 
	//指定删除元素并判断是否删除成功
	//可以使用erase的返回值统计待删除元素出现的次数来判断是否删除成功
	int x = 0;
	cout << "输入你要删除的元素:";
	cin >> x;
	int num = s.erase(x);
	if (num)
	{
		cout << "删除成功" << endl;
		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	else
	{
		cout << "删除失败" << endl;
		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
	}
 
	return 0;
}

 

迭代器删除 

//删除
int main()
{
	set<int> s;
	s.insert({ 2,4,5,2,6,8,10,15 });
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
 
	//指定删除元素并判断是否删除成功
	//可以使用erase的返回值统计待删除元素出现的次数来判断是否删除成功
	int x = 0;
	cout << "输入你要删除的元素:";
	cin >> x;
 
	//使用迭代器删除
	//如果未查找到则直接返回迭代器尾部
	auto pos = s.find(x);
	if (pos != s.end())
	{
		s.erase(x);
		cout << "删除成功" << endl;
		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	else
	{
		cout << "删除失败" << endl;
		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
	}
 
	return 0;
}

迭代器区间删除 

//迭代器区间删除
int main()
{
	set<int> s;
	for (int i = 0; i < 10; i++)
	{
		s.insert(i * 10);
	}
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
 
	//删除30到50区间的数据
	//取出 >=30 的迭代器指针,包括30
	auto low = s.lower_bound(30);
 
	//取出 >50 的迭代器指针,不包括50
	auto up = s.upper_bound(50);
 
	s.erase(low, up);
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
 
	return 0;
}

 


5. multiset和set的差异 

multiset和set的使⽤基本完全类似,主要区别点在于multiset⽀持值冗余(也就是不去重),那么insert/find/count/erase都围绕着⽀持值冗余有所差异,具体参看下⾯的样例代码理解

相比set不同的是,multiset是排序,但是不去重  

 multiset相比set不同的是,x可能会存在多个,find查找中序的第⼀个 

当在左子树找到符合的值后继续从该值的左子树寻找,直到找不到为止,这时的节点就是中序的第一个

#include<iostream>
#include<set>
using namespace std;
int main()
{
	// 相⽐set不同的是,multiset是排序,但是不去重 
	multiset<int> s = { 4,2,7,2,4,8,4,5,4,9 };
	auto it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	// 相⽐set不同的是,x可能会存在多个,find查找中序的第⼀个 
	int x;
	cin >> x;
	auto pos = s.find(x);
	while (pos != s.end() && *pos == x)
	{
		cout << *pos << " ";
		++pos;
	}
	cout << endl;
	// 相⽐set不同的是,count会返回x的实际个数 
	cout << s.count(x) << endl;
	// 相⽐set不同的是,erase给值时会删除所有的x 
	s.erase(x);
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}


未完待续~

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

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

相关文章

【数据库设计】逻辑结构设计

E-R实体集的转换 概念结构设计之后就是对E-R图进行逻辑结构设计&#xff1a;即将E-R图转化成关系的过程。逻辑结构设计主要用于数据库管理系统上&#xff0c;为了让数据在计算机系统中更好地表示。 此设计过程用到的数据模型有&#xff1a;除了前面讲过的关系模型还有层次模型…

如何看一个flutter项目的具体flutter版本

查看pubspec.lock文件 这个项目实际运行的就是 flutter 3.16.6 版本的

详解Java之Spring MVC篇一

目录 Spring MVC 官方介绍 MVC RequestMapping 传递参数 无参数 单个参数 针对String类型 针对Integer类型 针对int类型 针对自定义类型 多个参数 参数重命名 参数强制一致 参数不强制一致 传递数组 ​编辑传递List ​编辑 传递JSON ​编辑 从路径中获取参…

你们想要的格姗导航网站终于开源了!

关注小格子的读者们&#xff0c;应该都知道&#xff0c;小格子自己做了一个导航网站。 通过这几天的代码和文档整理&#xff0c;决定把导航网站给大家开源。目前只开源基础版&#xff0c;大家可以根据此开源项目开发自定义导航。 格姗导航网站 一个基于 Spring Boot、MyBati…

文献阅读:通过深度神经网络联合建模多个切片构建3D整体生物体空间图谱

文献介绍 文献题目&#xff1a; 通过深度神经网络联合建模多个切片构建3D整体生物体空间图谱 研究团队&#xff1a; 杨灿&#xff08;香港科技大学&#xff09;、吴若昊&#xff08;香港科技大学&#xff09; 发表时间&#xff1a; 2023-10-19 发表期刊&#xff1a; Nature M…

Vs配置opencv库 实例,opencv选用4.9.0版本,vs版本是2022社版,学习笔记不断更新

课程链接 贾志刚老师opencv入门课程 备注&#xff1a;由于课程好几年前了&#xff0c;直接将环境配置为opencv4.9.0vs22 参考&#xff1a; 参考搭建环境 opencv下载环境&#xff1a;opencv vs22opencv4.9.0 创建一个文件夹 并修改下下面的目录&#xff0c;我的目录是F:\opencv…

LinkedList和链表之刷题课(上)

在上一节,我们自己实现了一个单链表的结构,接下来我们来写几个面试题巩固一下 1. 删除链表中等于给定val的所有结点 解析题目: 如图,我们需要删除所有的值为12的结点 在head非空的情况下,我们删除一个结点,首先要找到这个结点,然后把这个结点的前面一个结点的next指向这个节点…

neutron组件

1.实现虚拟交换机有两种方式 2.HCS网络节点 华为 HCS 将网络节点单独部署&#xff0c;且部署两台(主备部署) 两张万兆网卡&#xff0c;否则检测无法通过 L3 agent 部署在哪个节点&#xff0c;哪个节点就是网络节点 DHCP agent metadata agent 3.neutron概念 3.1Neutron支持…

10. DAX 时间函数之实战

在实际代码过程中&#xff0c;总会遇到各种需求&#xff0c;往往需要一个或者多个函数一起实现目的。在下面的过程中&#xff0c;我尽量使用简洁而优美的代码&#xff0c;来实现各个目的。 首先准备数据&#xff0c;使用 1. DAX 时间函数--生成日期表 中的 GENERATE CALENDAR …

服务器卸载 mysql

服务器卸载 mysql 1.卸载安装的mysql #查看安装的mysql rpm -qa|grep -i mysql在这里插入图片描述 #卸载 rpm -ev 名称 --nodeps rpm -ev mysql-libs-8.0.26-1.module_el8.4.0915de215114.x86_64 --nodeps2.删除相关文件 find / -name mysql rm -rf /var/lib/mysql3.删除配…

西南交通大学计算机软件专业上岸难度分析

C哥专业提供——计软考研院校选择分析专业课备考指南规划 西南交通大学计算机科学与技术2024届考研难度整体呈现"稳中有升"的态势。学硕实际录取33人&#xff0c;复试分数线362分&#xff0c;复试录取率71.74%&#xff1b;专硕&#xff08;计算机技术&#xff09;实际…

Java 输入与输出(I/O)流的装饰流【处理流】

Java I/O流的装饰流 按照Java 输入与输出&#xff08;I/O)流的处理功能&#xff1a;I/O流可分为低级的节点流和高级的装饰流&#xff08;又称处理流&#xff09;。 节点流是直接从数据源&#xff08;数据源可以是文件、数组、内存或网络&#xff09;读/写数据的输入输出流&am…

021_Thermal_Transient_in_Matlab统一偏微分框架之热传导问题

Matlab求解有限元专题系列 固体热传导方程 固体热传导的方程为&#xff1a; ρ C p ( ∂ T ∂ t u t r a n s ⋅ ∇ T ) ∇ ⋅ ( q q r ) − α T d S d t Q \rho C_p \left( \frac{\partial T}{\partial t} \mathbf{u}_{\mathtt{trans}} \cdot \nabla T \right) \nab…

三个必须了解的知乎知+广告账户知识!

作为国内领先的问答社区&#xff0c;知乎以其高质量的内容和深度讨论吸引了大量专业和兴趣导向的用户群体。对于希望精准触达目标用户的广告主来说&#xff0c;知乎的信息流广告无疑是一个不可多得的营销渠道&#xff0c;云衔科技助力企业知乎广告开户投放及代运营服务。 1. 知…

【rom分享】PSP体育游戏大众高尔夫玩法介绍,不要错过

各位新老观众大家好&#xff0c;今天我将介绍知名掌机PSP的所有游戏&#xff0c;PSP的游戏库非常庞大&#xff0c;随着PSP模拟器的普及&#xff0c;你可以在安卓和苹果两大平台的移动设备上游玩&#xff0c;也可以在PC上面游玩&#xff0c;当然你也可以收藏一个PSP掌机进行游玩…

python3的语法及入门(近7000字,耐心看包全,看完记得点赞)!

1. Python3 基础语法 缩进&#xff1a;Python 使用缩进来表示代码块&#xff0c;通常使用 4 个空格。 语句&#xff1a;一行代码就是一个语句。 变量&#xff1a;不需要声明类型&#xff0c;直接赋值即可。 2. Python3 基本数据类型 Python 中的基本数据类型包括整数、浮点…

Shell学习——shell中的变量

目录 一、父shell和子shell&#xff1a; 二、系统预定变量 定义方式&#xff1a; 脚本举例 ​编辑 四、只读变量 五、撤销变量 六、小结 七、特殊变量 $n $# $*、$ $? 一、父shell和子shell&#xff1a; 由于shell的原理可以理解为套娃&#xff0c;因此有父shell…

【实战案例】Django框架连接并操作数据库MySQL相关API

本文相关操作基于上次操作基本请求及响应基础之上【实战案例】Django框架基础之上编写第一个Django应用之基本请求和响应 Django框架中默认会连接SQLite数据库&#xff0c;好处是方便无需远程连接&#xff0c;打包项目挪到其他环境安装一下依赖一会就跑起来&#xff0c;但是缺点…

你知道吗?这个岗位只招2人,但HR那边却收到了1w份简历

引言 在当前经济环境下&#xff0c;求职者面临的挑战越来越大。互联网行业尤其如此&#xff0c;许多人挤破头都想进入大厂&#xff0c;但竞争异常激烈。如今的就业市场确实变得异常艰难。然而&#xff0c;随着AI大模型技术的兴起&#xff0c;对于那些掌握了相关技能的专业人才…

学习笔记——交换——STP(生成树)基本概念

三、基本概念 1、桥ID/网桥ID (Bridege ID&#xff0c;BID) 每一台运行STP的交换机都拥有一个唯一的桥ID(BID)&#xff0c;BID(Bridge ID/桥ID)。在STP里我们使用不同的桥ID标识不同的交换机。 (2)BID(桥ID)组成 BID(桥ID)组成(8个字节)&#xff1a;由16位(2字节)的桥优先级…