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;//空的setint 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.rhkb.cn/news/302249.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

构建第一个ArkTS之页面和自定义组件生命周期

在开始之前&#xff0c;我们先明确自定义组件和页面的关系&#xff1a; 自定义组件&#xff1a;Component装饰的UI单元&#xff0c;可以组合多个系统组件实现UI的复用&#xff0c;可以调用组件的生命周期。页面&#xff1a;即应用的UI页面。可以由一个或者多个自定义组件组成&…

vue3+Ts+Ant Design Vue +天地图组件封装

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vue3TsAntDesign-Vue组件天地图组件的封装 示例图 首先,在index.html引入天地图资源,vue3选择v4版本 <script src"http://api.tianditu.gov.cn/api?…

Spring之AOP的详细讲解

目录 一.SpringAOP是什么&#xff1f; 1.1理论知识点 1.2简单的AOP例子 二.SpringAOP的核心概念 2.1切点(Pointcut) 2.2通知&#xff08;Advice&#xff09; 2.3切⾯(Aspect) 2.4通知类型 2.5切⾯优先级 Order 2.6切点表达式 2.6.1 execution表达式 2.6.2annotati…

深入C语言内存:数据在内存中的存储

一、数据类型 1. unsigned&#xff1a;无符号数类型 当一个数是无符号类型时&#xff0c;那么其最高位的1或0&#xff0c;和其它位一样&#xff0c;用来表示该数的大小。 2.signed&#xff1a;有符号数类型 当一个数是有符号类型时&#xff0c;最高数称为“符号位”。符号位为1…

k8s知识

k8s是用于容器编排和管理的&#xff0c;docker或者ctr是k8s的运行时&#xff0c;k8s通过容器运行时来启动容器&#xff0c;容器启动需要镜像&#xff0c;镜像可以用docker构建&#xff0c;dockerfile就是用于自定义如何构建镜像&#xff0c;所以上面那套流水线就是先用dockerfi…

【Linux】TCP编程{socket/listen/accept/telnet/connect/send}

文章目录 1.TCP接口1.1socket文档 1.2listen拓&#xff1a;端口号8080 1.3accept拓&#xff1a;今天全局函数 1.4读写接口1.5telnet1.一个客户端2.两个客户端 1.6ulimit -a1.7常识回顾1.8connect1.9拓&#xff1a;客户端的ip和地址什么时候被分配&#xff1f;1.10拓&#xff1a…

Linux应用开发(3):Linux时间操作(time、mktime、localtime等)

1. 简述 在Linux系统中&#xff0c;时间操作函数是编程中经常使用的一部分&#xff0c;它们允许程序获取和设置系统时间&#xff0c;以及对时间进行各种处理。以下是一些常用的时间操作函数的详细介绍。 2. 时间操作 &#xff08;1&#xff09;time(): 获取1970年1月1日以来的…

18 Games101 - 笔记 - 高级光线传播与复杂外观建模

**18 ** 高级光线传播与复杂外观建模 本章虽然是高级光线传播与复杂外观建模&#xff0c;但是都没有展开讲&#xff0c;不涉及具体的计算。 高级光线传播 无偏的光线传播&#xff1a;如果无论样本多少&#xff0c;算出来的期望值永远是对的。例如蒙特卡洛积分&#xff0c;它…

vue3中使用webstocket

1.在项目中创建webstocket.ts文件 export default class SocketService {// 单例static instance null;static get Instance() {if (!this.instance) {this.instance new SocketService();}return this.instance;}// 和服务端连接的socket对象ws null;// 存储回调函数callB…

nestjs 全栈进阶--nest生命周期

视频教程 12_nestjs生命周期_哔哩哔哩_bilibili 所有应用程序元素都有一个由 Nest 管理的生命周期。Nest 提供了生命周期钩子&#xff0c;提供了对关键生命时刻的可见性&#xff0c;以及在关键时刻发生时采取行动(在你的module&#xff0c;injectable或者controller中注册代码…

ddres( ) 组站星双差方程和设计矩阵

1 ddres( )参数介绍 rtklib中进行的单频解算 双差观测值&#xff0c;单差的模糊度 单频点双差 DD (double-differenced) phase/code residuals ------------------------------ x 模糊度 P 方差-协方差阵 sat 共识卫星列表 ns 共识卫星数量 y…

Qt | Q_PROPERTY属性和QVariant 类

一、属性基础 1、属性与数据成员相似,但是属性可使用 Qt 元对象系统的功能。他们的主要差别在于存取方式不相同,比如属性值通常使用读取函数(即函数名通常以 get 开始的函数)和设置函数(即函数名通常以 set 开始的函数)来存取其值,除此种方法外,Qt 还有其他方式存取属性值…

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…

DDD 的四层领域模型是怎样的?包含哪些基础概念?

DDD的四层领域模型如下所示&#xff1a; 展现层&#xff1a;这一层负责向用户显示信息和解释用户命令&#xff0c;完成前端界面逻辑。并将用户请求传递给应用层。应用层&#xff1a;这一层是很薄的一层&#xff0c;负责协调领域层中的领域对象&#xff0c;组成具体应用场景。应…

深度解析Elasticsearch索引数据量过大的优化与部署策略

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 一. 分片和副本策略 1.1分片策略 1.1.1 数据量 1.1…

springCloudAlibaba集成gateWay实战(详解)

一、初识网关&#xff1f; 1、网关介绍 ​ 在微服务架构中&#xff0c;一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢&#xff1f;如果没有网关的存在&#xff0c;我们只能在客户端记录每个微服务的地址&#xff0c;然后分别去调用。这样的话…

python爬虫———urllibd的基本操作(第十二天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

画图理解JVM相关内容

文章目录 1. JVM视角下&#xff0c;内存划分2. 类内存分布硬核详解1. 获取堆内存参数2. 扫描堆内存&#xff0c;定位实例3. 查看实例所在地址的数据4. 找到实例所指向的类信息的地址5. 查看class信息6. 结论 3. Java的对象创建流程4. 垃圾判别算法4.1 引用计数法4.2 可达性分析…

【Redis】NoSQL之Redis的配置和优化

关系型数据库与非关系型数据库 关系型数据库 关系型数据库是一个结构化的数据库&#xff0c;创建在关系型模型&#xff08;二维表&#xff09;的基础上&#xff1b;一般面向于记录&#xff1b; SQL语句(标准数据查询语句)就是一种基于关系型数据库的语言&#xff0c;用于执行…

Mysql底层原理五:如何设计、用好索引

1.索引的代价 空间上的代价 时间上的代价 每次对表中的数据进⾏增、删、改操作时&#xff0c;都需要去修改各个B树索引。⽽且我们讲过&#xff0c;B树每层节点都是按照索引列的值从⼩到⼤的顺序排序⽽组成了双 向链表。不论是叶⼦节点中的记录&#xff0c;还是内节点中的记录&a…