C++set和map详细介绍

文章目录

  • 前言
  • 一、关联式容器和序列式容器
  • 二、set
    • 1.set文档介绍
    • 2.set成员函数
      • 1.构造函数
      • 2.迭代器
      • 3.容量
      • 4.修改
      • 5.其他
  • 三.multiset
  • 四.map
    • 1.map文档介绍
    • 2.map成员函数
      • 1.构造
      • 2.insert插入
      • 3.count
      • 4.迭代器
      • 5.【】和at
  • 五.multimap
  • 总结


前言

在本篇文章中,我们将会学到关联式容器set,multiset,map,multimap。
其中前两种容器对应我们上篇二叉树文章中的K模型,后两者容器对应我们的KV模型。
我们来详细看一下吧!!!

一、关联式容器和序列式容器

我们在之前学习到的vector,list,stack,queue等都属于序列式容器,底层是线性结构,只存储数据。
关联式容器也是也是用来存储数据的,不过存储的是<K,V>这样一个键值对。

二者有什么区别呢??
⭐️序列式容器中仅仅存储一个值,关联式容器中存储一个键值对
⭐️序列式容器内部不涉及排序,关联式容器内部自动排序
⭐️序列式容器的查找按照自身的值进行相关查找,关联式容器根据K的值进行查找。
并且关联式速度比序列式容器查找快很多。

键值对

键值对是由<K,V>两个值构成的,其中K叫做键值,V就是与之对应的数据。
比如在日常生活中我们用到的英汉字典,就是一个键值对,每个英文单词对应一个中文翻译。英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义。

在C++中STL中已经帮助我们实现了键值对---->(pair)

在这里插入图片描述
T1和T2可以是两个不同的类型,访问是值是first,第二个值是second。

二、set

1.set文档介绍

在这里插入图片描述

看一下模板参数

🌟T:底层存储的数据类型
🌟Compare:比较方式,默认按照小于方式比较
🌟Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理

set文档介绍

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

看一下要点:
⭐️⭐️ set底层是一颗二叉树,内容可以删除,但不允许修改,查找某个元素时间复杂度为logN。
⭐️⭐️ set中不允许出现重复元素,本质是排序+去重
⭐️⭐️ set的迭代器遍历是一个有序序列
⭐️⭐️ set存的是一个值value,但是在底层也是一个键值对,不过这个键值对两个值都相同,即<value,value>,我们在使用时,只需要插入就可以,不需要构建键值对。
⭐️⭐️set比较默认按照小于比较
⭐️⭐️对于unique算法,去重相邻重复元素,去重之前需要先排序,才可以达到去重的效果。并不会改变容器的大小,随后调用erase删除这些重复元素。
nums.erase(unique(nums.begin(), nums.end()), nums.end());

2.set成员函数

1.构造函数

在这里插入图片描述
🌟🌟空的set

set< int >s;

🌟🌟迭代器区间构造set

set< int >s(s2.begin(),s2.end());

🌟🌟拷贝构造set

set< int >s(s2);

2.迭代器

在这里插入图片描述

遍历

🌟🌟迭代器遍历

set<int>s;
int a[] = { 8, 3, 1,1,2,3,4,5,6,7,10, 6, 4, 7, 14, 13 };
for (auto& e : a)
{
	s.insert(e);
}
//迭代器遍历
set<int>::iterator it = s.begin();
while (it != s.end())
{
	cout << *it << " ";
	it++;
}
cout << endl;

我们可以看到确实完成了去重任务。
在这里插入图片描述

🌟🌟范围for

	for (auto& e : s)
	{
		cout << e << " ";
	}

3.容量

🌟 🌟 empty
在这里插入图片描述
判断set是否为空

🌟 🌟 size
在这里插入图片描述
找出set中有效元素的个数。

4.修改

🌟 🌟insert
在这里插入图片描述

第一个:直接插入一个值
第二个:在某个位置插入一个值
第三个:插入一个迭代器区间

看起来很简单蛮,我们来看点诡异的,第一个的返回值
pair<iterator,bool> 返回一个键值对??

我们看一下文档的介绍
在这里插入图片描述
如果插入成功就返回插入结点的迭代器,并且返回true。
如果插入失败,也就是set中有这个元素,返回set中这个元素的迭代器,返回false。

🌟 🌟erase
在这里插入图片描述

第一个删除某个迭代器位置的值
第二个删除这个值,注意这个返回值,返回set中val这个元素的个数。
第三个删除一段迭代器区间

第一个删除和第二个删除有什么不同呢??

看一下这段代码,运行结果是什么??

	set<int>s;//空的set
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	for (auto& e : a)
	{
		s.insert(e);
	}
	for (auto& e : s)
	{
		cout << e << " ";
	}
	cout << endl;
	//查找删除
	set<int>::iterator pos = s.find(3);
	s.erase(pos);
	for (auto& e : s)
	{
		cout << e << " ";
	}
	cout << endl;

在这里插入图片描述
成功的把3删除了,那我们如果删除一个不存在的值呢???

	pos = s.find(30);
	s.erase(pos);
	for (auto& e : s)
	{
		cout << e << " ";
	}
	cout << endl;

在这里插入图片描述
系统直接崩溃了,所以我们需要加判断!!!
在这里插入图片描述
那如果用第二种方法直接删除一个不存在的值呢??

s.erase(20);

在这里插入图片描述
我们发现并没有报错。

对于直接删除:在就删除,不在不做任何处理

我们要注意这两个的区别!!!!

🌟 🌟swap
在这里插入图片描述
交换两个set的值
🌟 🌟clear
在这里插入图片描述
清空set中的元素

5.其他

🌟 🌟find
在这里插入图片描述
查找某个值,如果存在返回对应的迭代器区间,不存在返回end的迭代器。
🌟 🌟count在这里插入图片描述
记录val这个值的个数,在set中出现了多少次。返回set中值为x的元素的个数

🌟 🌟lower_bound
在这里插入图片描述
记录大于等于val的迭代器
如果这个值存在,返回这个值的迭代器。
如果这个值不存在,返回大于这个值的迭代器。

在这里插入图片描述
在set中存在3,解引用就返回3。查找9,9不存在,就返回下一个

🌟 🌟upper_bound
在这里插入图片描述
upper_bound也是同样的道理,但是不同的是,这个返回大于val的迭代器。在这里插入图片描述

三.multiset

multiset本质和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底层结构为二叉搜索树(红黑树)

与set相比,不同的是,multiset允许重复的值存在,本质就是排序。其他的都与set相同。

	set<int>s;
	int a[] = { 8, 3, 1,1,2,3,4,5,6,7,10, 6, 4, 7, 14, 13 };
	for (auto& e : a)
	{
		s.insert(e);
	}
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	for (auto& e : s)
	{
		cout << e << " ";
	}

看一下运行结果
在这里插入图片描述
我们再来看一下一个的返回值
在这里插入图片描述
这个地方就有很大的意义了。
在这里插入图片描述
count的意义也就发挥出来了。

四.map

map就是对应我们二叉树中的KV模型

1.map文档介绍

在这里插入图片描述
看一下模板参数
在这里插入图片描述
包括四个值:
🌟Key:键值对中的key值
🌟T:键值对中的value值
🌟Compare:比较器类型,一般是按照小于比较。如果是自定义类型,需要自己传递这个比较方式,达到要求。
🌟Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的
空间配置器

set文档介绍

  1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
  2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:
    typedef pair<const key, T> value_type;
  3. 在内部,map中的元素总是按照键值key进行比较排序的。
  4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
  5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
  6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))

看一下要点:
🌟🌟map中存储的是一个键值对,键值对中第一个元素,也就是key,根据key值进行排序,确定唯一元素。
第二个值value,与key的内容关联。
🌟🌟元素不可以修改key的值,但是可以修改value的值。
🌟🌟支持下标访问,把key放在[ ]中,可以找到与之对应的value元素。

2.map成员函数

这其中与很多和set的成员函数相同,在这里我就不再重复阐述了。
接下来主要讲述一些不同点,以及重点内容。
在这里插入图片描述

1.构造

🌟🌟1.有名构造
    pair<string, string>p = { “pear”, “梨” };
    m.insert( p);
🌟🌟2.匿名构造
   m.insert(pair<string, string>(“apple”, “苹果”));
🌟🌟3.make_pair
    m.insert(make_pair(“banana”, “香蕉”));
在这里插入图片描述
c++98新增的,本质就是一个函数模板

🌟🌟4.c++11多参数隐式类型转换
    m.insert({“strawberrier” ,“草莓”});

2.insert插入

我们看一下官方文档
在这里插入图片描述
我们主要看一下第一条:

插入的是一个pair类型,返回值也是一个pair类型

我们来看一下有关返回值的介绍
在这里插入图片描述

如果插入到元素存在,返回值中的iterator就指向这个存在的位置的迭代器,bool值为false
如果插入元素不存在,返回值中的iterator就指向这个新插入的位置的迭代器,bool值为true
这里的元素插入是看key的值,与value无关。

3.count

在这里插入图片描述
count返回key为x的键值在map中的个数,注意map中key是唯一的,因此该函数的返回值要么为0,要么为1,因此也可以用该函数来检测一个key是否在map中。

4.迭代器

我们注意一下map有两个值,我们再遍历的时候,不能只遍历一个,要把两个分开。


	for (auto& kv : m)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;

first代表pair第一个值,second代表pair第二个值。

5.【】和at

map中支持【】访问元素。

如果我们想要统计水果出现的次数
第一步:先看这个水果在不在!!
第二步:如果不在,就把这一个键值对插入进去。如果在,就让vaule这个值加加。
最后遍历一边元素,就完成了

我们再map中不用折磨麻烦,我们看一下这个巧妙的代码。

// 统计水果出现的次数
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
map<string, int> m;
for (auto& e : arr)
{
	m[e]++;
}

m[e]++;就完成了操作。

我们来看一下怎末实现的??
在这里插入图片描述
【】的返回值是value类型,参数是一个key类型。

在文档中还有这样一段话,我们来剖析一下。
在这里插入图片描述
在这里插入图片描述

这个【】需要调用insert,insert上面我们已经介绍过了,拆分来看一下
🌟insert(make_pair(k,mapped_type()))这个是insert的原型,插入一个键值对,key值必须传入,如果value不传入,采用缺省值。
这个k存在,就返回这个k这个值的迭代器,不存在,就返回新插入这个k的迭代器。
🌟this->insert(make_pair(k,mapped_type()))调用这个返回值pair
🌟(this->insert(make_pair(k,mapped_type()))).first调用这个返回值的pair的第一个元素iterator,迭代器本身就是指针。
🌟(*((this->insert(make_pair(k,mapped_type()))).first)).second
这个迭代器指向的第二个元素,就是value.

通过这种方式我们就拿到了value的值
如果不存在,插入成功,返回新插入元素的迭代器
如果已存在,插入失败,返回该key所在位置的迭代器
operator[]函数最后将insert返回值键值对中的value返回

在元素访问时,有一个与operator[]类似的操作at()(该函数不常用)函数,都是通过key找到与key对应的value然后返回其引用
不同的是:当key不存在时,operator[]用默认value与key构造键值对然后插入,返回该默认value,at()函数直接抛异常。

我们看一下这段代码的结果是什么??

	map<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("sort", "xxx"));

在这里插入图片描述

只与key的值有关,与value无关。
key相同,value不同,不会插入也不会更新

这个【】就有很多功能了,也可以插入,也可以查找,也可以修改
在这里插入图片描述

五.multimap

map和multimap没有太大区别
在这里插入图片描述

  1. Multimaps是关联式容器,它按照特定的顺序,存储由key和value映射成的键值对<key,value>,其中多个键值对之间的key是可以重复的。
  2. 在multimap中,通常按照key排序和惟一地标识元素,而映射的value存储与key关联的内容。key和value的类型可能不同,通过multimap内部的成员类型value_type组合在一起,value_type是组合key和value的键值对:
    typedef pair<const Key, T> value_type;
  3. 在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对key进行排序的。
  4. multimap通过key访问单个元素的速度通常unordered_multimap容器慢,但是使用迭代器直接遍历multimap中的元素可以得到关于key有序的序列。
  5. multimap在底层用二叉搜索树(红黑树)来实现

multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以重复的。
multimap中没有重载operator[]操作

总结

以上就是今天要讲的内容,本文仅仅详细介绍了C++map和set的相关内容。希望对大家的学习有所帮助,仅供参考 如有错误请大佬指点我会尽快去改正 欢迎大家来评论~~ 😘 😘 😘

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

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

相关文章

DC-DC芯片D1509适用于工控主板、TV板卡、安卓主板、车载功放电源等产品方案应用。

一、应用领域 适用于工控主板、TV板卡、安卓主板、车载功放电源等产品方案应用。 二、功能介绍 D1509是芯谷科技推出的一款输入耐压40V、输出电压1.23-37V可调、输出电流最大2.0A的高效率、高精度DC-DC芯片&#xff0c;其输出电压有固定3.3V、5.0V和12.0V的版本&#xff…

BM96 主持人调度(二)(贪心算法)

一开始写的时候忘了给start、end数组赋值了 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可** 计算成功举办活动需要多少名主持人* param n int整型 有n个活动* param start…

C#:用定时器监控定时器,实现中止定时器正在执行的任务,并重启

Windows服务中使用的比较多的是定时器&#xff0c;但这种定时任务有个比较大的毛病&#xff1a;有时会莫名其妙地停止执行&#xff08;长时间执行不完&#xff0c;假死&#xff09;&#xff0c;必须得手工重启Windows服务才能恢复正常。这个就太麻烦了。 有没有办法来实现定时…

Vue3快速上手 详细内容

Vue3快速上手 1.Vue3简介 2020年9月18日&#xff0c;Vue.js发布3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;海贼王&#xff09;耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址&#xff1a;Release v3.0.0 One Piece vuejs/core Git…

什么是国密SSL证书,和其他SSL证书的区别?

我们要了解什么是SSL证书。SSL&#xff08;Secure Sockets Layer&#xff0c;安全套接层&#xff09;是一种安全协议&#xff0c;主要用于在互联网上对通信双方进行身份验证以及保障数据的安全传输。而SSL证书则是由权威的数字证书认证机构签发的&#xff0c;用于证明网站身份的…

【Linux】磁盘与文件系统管理

目录 一、 磁盘结构 1. 数据结构 2. 物理结构 3. 硬盘的接口类型 二、 如何使用Linux中的磁盘 三、 文件系统 四、 磁盘分区 1. MBR分区 2. 分区的优缺点 3. 磁盘及分区的管理工具 五、格式化与挂载 1. 格式化 2. 挂载 六、实例演示 1. 演示分区格式化挂载 2. …

C语言写流星雨代码

目录 需要包含的头文件 图片素材的路径 初始化背景图片 报错怎么解决&#xff1f; 初始化流星雨 放置流星雨图片 让流星雨动起来 总不能让流星砸到地面吧 是不是应该再来一点背景音乐&#xff1f; 所有代码 需要包含的头文件 IMAGE img;//创建流星雨的图片变量void…

HTML - 请你说一下如何阻止a标签跳转

难度级别:初级及以上 提问概率:55% a标签的默认语义化功能就是超链接,HTML给它的定位就是与外部页面进行交流,不过也可以通过锚点功能,定位到本页面的固定id区域去。但在开发场景中,又避免不了禁用a标签的需求,那么都有哪些方式可以禁用…

Jmeter针对多种响应断言的判断

有时候response返回的结果并非一种&#xff0c;有多种&#xff0c;需要对这几种进行判断的时候需要使用Bean Shell。 &#xff08;1&#xff09;首先获取响应数据 String response prev.getResponseDataAsString(); ResponseCode 响应状态码 responseHeaders 响应头信息 res…

DFS:深搜+回溯+剪枝解决排列、子集问题

创作不易&#xff0c;感谢三连支持&#xff01;&#xff01; 一、全排列I . - 力扣&#xff08;LeetCode&#xff09; class Solution { public://全局变量vector<vector<int>> ret;vector<int> path;bool check[6];vector<vector<int>> perm…

虚拟网络设备性能优化

在现代网络架构中&#xff0c;虚拟网络设备扮演着越来越重要的角色&#x1f310;&#xff0c;特别是在云计算☁️和容器化技术&#x1f4e6;广泛应用的背景下。虚拟网络设备如虚拟以太网设备&#xff08;veth&#xff09;、虚拟交换机&#xff08;vSwitch&#xff09;、和虚拟路…

YOLOv9综合指南

YOLOv9是YOLO系列中用于实时目标检测的最新进展&#xff0c;引入了可编程梯度信息&#xff08;PGI&#xff09;和通用高效层聚合网络&#xff08;GELAN&#xff09;等新技术来解决信息瓶颈并提高检测精度和效率。 在这篇文章中&#xff0c;我们研究了 YOLOv9 的一些关键优势。 …

Java并发编程: Java线程组(ThreadGroup)

文章目录 一、介绍二、线程组特性1、关联性&#xff08;1&#xff09;一级关联性&#xff08;2&#xff09;多级关联性 2、自动归属属性3、根线程组 三、线程组作用1、统一异常处理机制 一、介绍 Java线程组&#xff08;ThreadGroup&#xff09;是一种用于组织和管理线程的机制…

【计算机毕业设计】在线商品管理系统的设计与实现——后附源码

&#x1f389;**欢迎来到琛哥的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 琛哥&#xff0c;一名来自世界500强的资深程序猿&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 琛哥在深度学习任务中展现出卓越的能力&a…

代码随想录算法训练营第三十四天| LeetCode 1005.K次取反后最大化的数组和、134. 加油站、135. 分发糖果

一、LeetCode 1005.K次取反后最大化的数组和 题目链接/文章讲解/视频讲解&#xff1a;https://programmercarl.com/1005.K%E6%AC%A1%E5%8F%96%E5%8F%8D%E5%90%8E%E6%9C%80%E5%A4%A7%E5%8C%96%E7%9A%84%E6%95%B0%E7%BB%84%E5%92%8C.html 状态&#xff1a;已解决 1.思路 还是那个…

基于SpringBoot+vue的在线商城系统+论文+免费远程调试

基于SpringBootvue的在线商城系统034(含源码 数据库文档免费送&#xff09; 开发系统:Windows10 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springb…

【SCI绘图】【热力图系列1 R】多特征相关性分析热力图R语言实现

SCI&#xff0c;CCF&#xff0c;EI及核心期刊绘图宝典&#xff0c;爆款持续更新&#xff0c;助力科研&#xff01; 本期分享&#xff1a; 【SCI绘图】【热力图系列1 R】多特征相关性分析热力图R语言实现 1.环境准备 library(gplots) library(RColorBrewer) 2.数据示例 ###…

MySQL典型示例

目录 1.使用环境 2.设计表 3.创建表 4.准备数据 5.查询 1.使用环境 数据库&#xff1a;MySQL 8.0.30 客户端&#xff1a;Navicat 15.0.12 2.设计表 假设我们已经建好了一个名为test的数据库。我们添加如下几个表&#xff1a;教师、课程、学生、班级、成绩。实体联系图设…

菜狗学前端之JS高级笔记

老样子。复制上来的图片都没了&#xff0c;想看原版可以移步对应资源下载(资源刚上传&#xff0c;还在审核中) (免费) JS高级笔记https://download.csdn.net/download/m0_58355897/89102910 一些前提概念 一 什么是js高级 js高级是对js基础语法的一个补充说明&#xff0c;本质…

C语言从入门到实战————文件操作

目录 前言 1. 为什么使用文件&#xff1f; 2. 什么是文件&#xff1f; 2.1 程序文件 2.2 数据文件 2.3 文件名 3. ⼆进制文件和文本文件&#xff1f; 4. 文件的打开和关闭 4.1 流和标准流 4.1.1 流 4.1.2 标准流 4.2 文件指针 4.3 文件的打开和关闭 5. 文…
最新文章