【C++】STL标准模板库容器set

news2024/12/26 14:29:50

🦄个人主页:修修修也

🎏所属专栏:C++

⚙️操作环境:Visual Studio 2022


目录

📌关联式容器set(集合)简介

📌set(集合)的使用

🎏set(集合)的模板参数列表

🎏set(集合)的构造函数

🎏set(集合)的迭代器

🎏set(集合)的容量

🎏set(集合)的修改操作

📌关联式容器multiset简介 

📌关联式容器multiset使用

结语


        在之前对STL的学习中,我们已经接触过STL中的部分容器,比如:vector、list、deque、forward_list(C++11)等,根据"数据在容器中的排列"特性,这些容器统称为序列式(sequence)容器,因为其底层为线性序列的数据结构,里面存储的是元素本身

        还有一种容器是关联式(associative)容器, 关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高

        下图列出了STL中的各种容器,以及其基层与衍生层的关系:


📌关联式容器set(集合)简介

        我们先来看一下cplusplus.com - The C++ Resources Network网站对set的文档介绍:

        总结一下:

  1. set是按照一定次序存储元素的容器。
  2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
  3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
  4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
  5. set在底层是用二叉搜索树(红黑树)实现的。

        注意:

  • 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对。
  • set中插入元素时,只需要插入value即可,不需要构造键值对。
  • set中的元素不可以重复(因此可以使用set进行去重)。
  • 使用set的迭代器遍历set中的元素,可以得到有序序列。
  • set中的元素默认按照小于来比较。
  • set中查找某个元素,时间复杂度为:$log_2 n$
  • set中的元素不允许修改(因为修改key可能会导致二叉搜索树结构被破坏)。
  • set中的底层使用二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))来实现。

📌set(集合)的使用

🎏set(集合)的模板参数列表

        set的模板参数及含义如下:


🎏set(集合)的构造函数

        set的构造函数及其功能如下:

        使用示例如下:

#include<iostream>
#include<vector>
#include<set>
using namespace std;

int main()
{
	//构造一个没有元素的空容器
	set<int> s1;
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v;
	v.push_back(2);
	v.push_back(5);
	v.push_back(1);
	v.push_back(4);
	v.push_back(3);

	//迭代器区间构造
	set<int> s2(v.begin(), v.end());
	for (auto e : s2)
	{
		cout << e << " ";
	}
	cout << endl;

	//拷贝构造
	set<int> s3(s2);
	for (auto e : s3)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

        运行效果如下:


🎏set(集合)的迭代器

        set的迭代器相关函数及其功能如下:

        使用示例如下:

int main()
{
	vector<int> v;
	v.push_back(2);
	v.push_back(5);
	v.push_back(1);
	v.push_back(4);
	v.push_back(3);

	//迭代器区间构造
	set<int> s(v.begin(), v.end());

	//正向迭代器
	set<int>::iterator it_b = s.begin();	//访问正向迭代器开始
	cout << *it_b << endl;

	set<int>::iterator it_e = s.end();		//访问正向迭代器结束
	--it_e;									
	cout << *it_e << endl;
	++it_e;

	while (it_b != it_e)
	{
		cout << *it_b << " ";			//使用正向迭代器遍历set
		++it_b;
	}
	cout << endl;

	//反向迭代器
	set<int>::reverse_iterator rit_b = s.rbegin();		//访问反向迭代器开始
	cout << *rit_b << endl;

	set<int>::reverse_iterator rit_e = s.rend();		//访问反向迭代器结束
	--rit_e;
	cout << *rit_e << endl;
	++rit_e;

	while (rit_b != rit_e)
	{
		cout << *rit_b << " ";			//使用反向迭代器遍历set
		++rit_b;
	}
	cout << endl;

	return 0;
}

        运行结果如下:


🎏set(集合)的容量

        set的容量相关函数及其功能如下:

        使用示例如下:

int main()
{
	//构造一个没有元素的空容器
	set<int> s1;
	cout << s1.empty() << endl;
	cout << s1.size() << endl;
	cout << s1.max_size() << endl;


	vector<int> v;
	v.push_back(2);
	v.push_back(5);
	v.push_back(1);
	v.push_back(4);
	v.push_back(3);

	//迭代器区间构造
	set<int> s2(v.begin(), v.end());
	cout << s2.empty() << endl;
	cout << s2.size() << endl;
	cout << s2.max_size() << endl;
	
	return 0;
}

        运行结果如下:


🎏set(集合)的修改操作

        set的修改相关函数及其功能如下:

函数声明功能介绍
pair<iterator, bool> insert(const value_type&x)在set中插入元素x,实际插入的是<x, x>构成的
键值对,如果插入成功,返回<该元素在set中的
位置,true>,如果插入失败,说明x在set中已经
存在,返回<x在set中的位置,false>
void erase ( iterator position )

删除set中position位置上的元素

size_type erase ( const key_type& x )删除set中值为x的元素,返回删除的元素的个数
void erase ( iterator first, iterator last )删除set中[first, last)区间中的元素
void swap ( set<Key,Compare,Allocator>& st )交换两个set中的元素
void clear ( )将set中的元素清空
iterator find ( const key_type& x ) const返回set中值为x的元素的位置
size_type count ( const key_type& x ) const返回set中值为x的元素的个数

        insert,erase,clear,find函数使用示例如下:

int main()
{
	//构造一个没有元素的空容器
	set<int> s1;
	//插入元素
	s1.insert(3);
	s1.insert(1);
	s1.insert(7);
	s1.insert(4);
	s1.insert(0);
	s1.insert(8);
	s1.insert(2);
	s1.insert(6);
	s1.insert(9);
	s1.insert(5);

	for (auto k : s1)
	{
		cout << k << " ";
	}
	cout << endl;

	set<int>::iterator pos = s1.find(1);
	//迭代器删除元素
	s1.erase(pos);
	for (auto k : s1)
	{
		cout << k << " ";
	}
	cout << endl;

	//key值删除元素
	s1.erase(3);
	for (auto k : s1)
	{
		cout << k << " ";
	}
	cout << endl;

	//迭代区间删除元素
	s1.erase(s1.begin(), s1.find(5));
	for (auto k : s1)
	{
		cout << k << " ";
	}
	cout << endl;

	//清空set中的元素
	s1.clear();
	for (auto k : s1)
	{
		cout << k << " ";
	}
	cout << endl;

	return 0;
}

        运行结果如下:

        swap函数使用示例如下:

int main()
{
	//构造两个没有元素的空容器
	set<int> s1;
	set<int> s2;
	//s1中插入元素
	s1.insert(3);
	s1.insert(1);
	s1.insert(4);
	s1.insert(0);
	s1.insert(2);

	cout << "s1 : ";
	for (auto k : s1)
	{
		cout << k << " ";
	}
	cout << endl;

	cout << "s2 : ";
	for (auto k : s2)
	{
		cout << k << " ";
	}
	cout << endl;

	//交换s1和s2的值
	s1.swap(s2);
	cout << "s1 : ";
	for (auto k : s1)
	{
		cout << k << " ";
	}
	cout << endl;

	cout << "s2 : ";
	for (auto k : s2)
	{
		cout << k << " ";
	}
	cout << endl;

	return 0;
}

        运行结果如下:

        count()函数的定义如下图: 

      

        count函数使用示例如下:

int main()
{
	//构造一个没有元素的空容器
	set<int> s1;
	//s1中插入元素
	s1.insert(3);
	s1.insert(1);
	s1.insert(4);
	s1.insert(0);
	s1.insert(2);

	cout << "s1 : ";
	for (auto k : s1)
	{
		cout << k << " ";
	}
	cout << endl;

	cout << s1.count(2) << endl;
	cout << s1.count(4) << endl;
	cout << s1.count(6) << endl;
	cout << s1.count(8) << endl;

	return 0;
}

        运行结果如下:


📌关联式容器multiset简介 

         我们先来看一下cplusplus.com - The C++ Resources Network网站对set的文档介绍:

        总结一下:

  1. multiset是按照特定顺序存储元素的容器,其中元素是可以重复的。
  2. 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成的键值对,因此value本身就是key,key就是value,类型为T). multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除。
  3. 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序。
  4. multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭代器遍历时会得到一个有序序列。
  5. multiset底层结构为二叉搜索树(红黑树)

        注意:

  1. multiset中再底层中存储的是<value, value>的键值对
  2. mtltiset的插入接口中只需要插入即可
  3. 与set的区别是,multiset中的元素可以重复,set是中value是唯一的
  4. 使用迭代器对multiset中的元素进行遍历,可以得到有序的序列
  5. multiset中的元素不能修改
  6. 在multiset中找某个元素,时间复杂度为$O(log_2 N)$
  7. multiset的作用:可以对元素进行排序

📌关联式容器multiset使用

        multiset的接口是和set一模一样的,区别在于具体的使用上:

        首先,multiset支持插入重复的键值key, 这就意味着multiset没有set的去重作用 :

int main()
{
	//构造一个没有元素的空容器set
	set<int> s;
	s.insert(3);
	s.insert(1);
	s.insert(5);
	s.insert(5);	//插入多个重复键值key
	s.insert(5);
	s.insert(4);
	s.insert(5);
	s.insert(2);
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	//构造一个没有元素的空容器multiset
	multiset<int> ms;
	ms.insert(3);
	ms.insert(1);
	ms.insert(5);
	ms.insert(5);	//插入多个重复键值key
	ms.insert(5);
	ms.insert(4);
	ms.insert(5);
	ms.insert(2);

	for (auto e : ms)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

        运行结果如下:

        同时,对于set模板里几乎没有什么意义的几个函数接口在multiset这里就可以得到很好的应用了,如:count,equal_range等函数:

        如下代码,我们利用count函数计算multiset中5出现的次数,并利用equal_range函数将其全部删除:

int main()
{
	//构造一个没有元素的空容器multiset
	multiset<int> ms;
	ms.insert(3);
	ms.insert(1);
	ms.insert(5);
	ms.insert(5);	//插入多个重复键值key
	ms.insert(5);
	ms.insert(4);
	ms.insert(5);
	ms.insert(2);

	for (auto e : ms)
	{
		cout << e << " ";
	}
	cout << endl;

	//计算5出现的次数
	cout << "5出现的次数: " << ms.count(5) << endl;

	//删掉所有的5
	pair<multiset<int>::iterator, multiset<int>::iterator> ret = ms.equal_range(5);	//这里ret的类型直接用auto也行
	multiset<int>::iterator left = ret.first;
	multiset<int>::iterator right = ret.second;
	ms.erase(left, right);

	for (auto e : ms)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

        运行结果如下:


结语

希望这篇关于 STL标准模板库容器set 的博客能对大家有所帮助,欢迎大佬们留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐

【C++】模拟实现二叉搜索(排序)树

【数据结构】C语言实现链式二叉树(附完整运行代码)

【数据结构】什么是二叉搜索(排序)树?

【C++】模拟实现priority_queue(优先级队列)

【C++】模拟实现queue

【C++】模拟实现stack

【C++】模拟实现list

【C++】模拟实现vector

【C++】标准库类型vector

【C++】模拟实现string类

【C++】标准库类型string

【C++】构建第一个C++类:Date类

【C++】类的六大默认成员函数及其特性(万字详解)

【C++】什么是类与对象?


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

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

相关文章

【算法题】72. 编辑距离-力扣(LeetCode)

【算法题】72. 编辑距离-力扣(LeetCode) 1.题目 下方是力扣官方题目的地址 72. 编辑距离 给你两个单词 word1 和 word2&#xff0c; 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作&#xff1a; 插入一个字符删除一个字符替换一个…

哈希算法以及容器实现

哈希 一&#xff0c;哈希算法1.什么是哈希2.哈希产生的原因3.常见哈希算法4.闭散列&#xff08; 哈希表&#xff09;1.线性探测2.二次探测 5.开散列&#xff08;哈希桶&#xff09;1.开散列插入2.开散列扩容 二&#xff0c;代码实现1.哈希表2.哈希桶1.迭代器的实现2.底层容器的…

C++ --- 模板为什么不能分离编译?

模板为甚么不能分离编译&#xff0c;但普通函数却可以&#xff1f; 一、前置知识二、普通函数能分离编译的原因三、模板不能分离编译的原因 一、前置知识 编译阶段: 源代码到目标代码&#xff1a; 编译器首先将源代码&#xff08;如C/C文件&#xff09;翻译成汇编语言&#x…

初学51单片机之I2C总线与E2PROM

首先先推荐B站的I2C相关的视频I2C入门第一节-I2C的基本工作原理_哔哩哔哩_bilibili 看完视频估计就大概知道怎么操作I2C了&#xff0c;他的LCD1602讲的也很不错&#xff0c;把数据建立tsp和数据保持thd&#xff0c;比喻成拍照时候的摆pose和按快门两个过程&#xff0c;感觉还是…

CentOs-Stream-9 设置静态IP外网访问

CentOs-Stream-9 设置静态IP&#xff0c;实现外网访问。这里面有些需要注意的地方&#xff0c;比如IP网段跟我们的宿主机不一样&#xff0c;需要查看具体的网络适配器网段&#xff0c;这样可以快速实现网络互通&#xff1b;另外它的网络配置文件也是不一样的。网络适配器对应的…

放弃 startActivityForResult,Activity Result API 优雅使用

放弃 startActivityForResult&#xff0c;Activity Result API 优雅使用 Activity Result API 是 androidx 中的一个新 api&#xff0c;旨在替代原有的 startActivityForResult 方法&#xff0c;用于在两个 Activity 或 Fragment 交换数据、获取返回结果。 过去如果 Activity…

了解独享IP的概念及其独特优势

在网络世界中&#xff0c;IP地址是用来识别和定位设备的标识符。独享IP是一种服务模式。使用代理服务器时&#xff0c;用户拥有一个不与其他用户共享的专用独立IP地址。与共享IP相比&#xff0c;独享IP为用户提供了更高的独立性和隐私保护。下面详细介绍独享IP的定义、工作原理…

OJ在线评测系统 后端 代码沙箱原生实现 初始化项目

代码沙箱Java原生实现 之前我们完成了快速的前端页面开发 重点是在后端 历史问题修复 Java原生代码沙箱实现 docker代码沙箱实现 解决历史遗留问题 代码编辑器切换语言失败 监听language属性 动态更改编辑器的语言 我们在这里实现的是一个线程形式的监听 watch(() > …

总结拓展十一:S4 HANA和ECC区别

第一节 S/4 HANA系统简介 SAP系统的产品线 R/1版本——主要财务模块R/3版本——基本实现全模块ECC6.0——2005年推出&#xff08;ECC是2004年推出&#xff09;HANA——数据库产品——属于内存数据库BW on HANA——HANA与数据分析相结合 拓展&#xff1a; 数据库类型&#x…

易盾滑块验证码

前言 这玩意我就搞定get请求和check请求&#xff0c;那个b接口的d参数还是有点问题&#xff0c;还有就是b接口的返回参数怎么用&#xff0c;是不是只是加了cookie我也不确定&#xff0c;所以有高手的话希望可以指导一下。我的虽然能够成功&#xff0c;但是只有前2次成功&#x…

ARM V8 A32常用指令集

文章目录 1. 算术指令1.1 加法命令ADD\ADDS1.2 带进位加法命令ADC\ADCS1.3减法命令SUB\SUBC1.4带借位减法命令SBC\SBCS 2.逻辑运算指令2.1逻辑与指令AND、ANDS2.2位清零指令BIC2.3逻辑或指令ORR\ORRS2.4逻辑异或指令2.5 逻辑左移LSL2.6逻辑右移LSR 3.比较指令3.1直接比较指令CM…

2024年华为杯研究生数学建模竞赛C题 波形机理建模+GBDT 完整文章代码|进阶可视化

2024年华为杯研究生数学建模竞赛C题 波形机理建模GBDT 完整文章代码|进阶可视化 全部问题已经更新完成&#xff0c;可视化图表20余张&#xff0c;代码量千余行&#xff0c;实在累到了… 由于篇幅原因&#xff0c;此处放出部分内容供参考~ 完整内容可以从底部名片的群中获取~ …

vue3监听子组件的生命周期

1.Vue3使用vue&#xff0c;vue2使用hook template:<compG vue:mounted"doSomething"></compG>script://监听子组件生命周期let doSomething (e: any) > {console.log("没有啊11", e);}; 2.打印结果

昇思MindSpore进阶教程--轻量化数据处理

大家好&#xff0c;我是刘明&#xff0c;明志科技创始人&#xff0c;华为昇思MindSpore布道师。 技术上主攻前端开发、鸿蒙开发和AI算法研究。 努力为大家带来持续的技术分享&#xff0c;如果你也喜欢我的文章&#xff0c;就点个关注吧 正文开始 在资源条件允许的情况下&#…

【趣学Python算法100例】数制转换

问题描述 给定一个M进制的数x&#xff0c;实现对x向任意一个非M进制的数的转换。 问题分析 要搞定这道题&#xff0c;关键在于学会不同数制之间的转换&#xff0c;主要是二进制、八进制、十六进制和十进制这几种。理解下面这几个概念非常重要&#xff1a; 基数&#xff1a;…

Go基础学习06-Golang标准库container/list(双向链表)深入讲解;延迟初始化技术;Element;List;Ring

基础介绍 单向链表中的每个节点包含数据和指向下一个节点的指针。其特点是每个节点只知道下一个节点的位置&#xff0c;使得数据只能单向遍历。 示意图如下&#xff1a; 双向链表中的每个节点都包含指向前一个节点和后一个节点的指针。这使得在双向链表中可以从前向后或从后…

Docker仓库搭建

目录 一、Docker Hub 二、私有Registry仓库搭建 1、下载并开启仓库镜像registry 2、Registry加密传输 3、建立一个registry仓库 4、为客户端建立证书 5、测试 6、为仓库建立登录认证 三、Harbor仓库搭建 Docker 仓库&#xff08;Docker Registry&#xff09; 是用于存…

8种数值变量的特征工程技术:利用Sklearn、Numpy和Python将数值转化为预测模型的有效特征

特征工程是机器学习流程中的关键步骤&#xff0c;在此过程中&#xff0c;原始数据被转换为更具意义的特征&#xff0c;以增强模型对数据关系的理解能力。 特征工程通常涉及对现有数据应用转换&#xff0c;以生成或修改数据&#xff0c;这些转换后的数据在机器学习和数据科学的…

书生大模型实战营学习[9] OpenCompass 评测 InternLM-1.8B 实践

准备工作 打开开发机&#xff0c;选择cuda11.7环境&#xff0c;A100选择10%&#xff0c;点击创建&#xff0c;然后进入开发机即可&#xff0c;和之前的操作一样。接下来创建环境&#xff0c;下载必要的依赖包 conda create -n opencompass python3.10 conda install pytorch2…

什么是网络安全自动化以及优势与挑战

目录 网络安全自动化的工作原理 网络安全自动化的好处 增强的安全功能 改善表现和姿势 降低安全成本 简化的安全合规性和审计 更好的端点管理 网络安全自动化的挑战 耗时且容易出错的安全流程 可见性降低&#xff0c;风险和成本增加 合规管理 有用的网络安全自动化…