【C++】- set和map的具体使用(multiset和multimap的介绍)

在这里插入图片描述
💖作者:小树苗渴望变成参天大树🎈
🎉作者宣言:认真写好每一篇博客💤
🎊作者gitee:gitee✨
💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法🎄
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录

  • 前言
  • 一、set
  • 二、set的接口以及使用方法
    • 2.1构造函数
    • 2.2迭代器
    • 2.3修改函数接口
    • 2.4操作函数
  • 三、map
    • 3.1插入和删除函数
    • 3.2operator[]函数
  • 四、set和map的应用
    • 4.1[349. 两个数组的交集](https://leetcode.cn/problems/intersection-of-two-arrays/description/)
    • 4.2[有效的括号](https://leetcode.cn/problems/valid-parentheses/description/)


前言

今天我们开始讲解进阶中的STL,这个容器相比较前面而言结构更加的复杂,但是用处也是更加的多,大家还记得我进阶的上一篇博客写的是什么吗??是二叉搜索树,所以今天这篇讲的STL就和上一篇博客讲的结构有关系,大家最好先提前看看二叉搜索树的博客,才能理解一些接口为什么会出现这样的效果,话不多说,我们开始介绍两个STL的容器-----set和map


在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、
forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。那什么是关联式容器?它与序列式容器有什么区别?

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

键值对
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义

template <class T1, class T2>
struct pair
{typedef T1 first_type;typedef T2 second_type;T1 first;T2 second;pair(): first(T1()), second(T2()){}pair(const T1& a, const T2& b): first(a), second(b){}
};

根据应用场景的不桶,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。下面一依次介绍每一个容器。

注意:set就是key的模型,map就是key_value的模型

一、set

注意:

  1. 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对。
  2. set中插入元素时,只需要插入value即可,不需要构造键值对。
  3. set中的元素不可以重复(因此可以使用set进行去重)。
  4. 使用set的迭代器遍历set中的元素,可以得到有序序列
  5. set中的元素默认按照小于来比较
  6. set中查找某个元素,时间复杂度为: l o g 2 n log_2 n log2n
  7. set中的元素不允许修改(为什么?)一会后面会说到
  8. set中的底层使用二叉搜索树(红黑树)来实现

我们一起来看看set在文档的中的具体介绍吧
在这里插入图片描述
T: set中存放元素的类型,实际在底层存储<value, value>的键值对。
Compare:set中元素默认按照小于来比较
Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理

我们看看提供了一个仿函数,原因是set在插入的时候需要进行内部的比较,每个类的比较的比较方式不一样,所以需要提供仿函数,来实现我们自己的比较逻辑。set的模板参数还是比较好理解,接下来我就带大家来看看set有哪些接口,具体是怎么使用吧.

二、set的接口以及使用方法

2.1构造函数

我们只需要研究构造函数,赋值和析构可以不用了解,都是和之前的一样的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这就是我们三种构造函数,通过监视窗口我们有没有发现一些细节的问题,我们看到v里面原本乱序的数据在s2中就编程有序了,而且原来有重复数据,而s2里面叶没有重复数据了,所以这是set一个比较需要了解的知识点,原因是set底层是类似于二叉搜索数的实现原理,才会变成有序的,但set里面有相同数据,就不允许插入了,在二叉搜索数的时候就已经知道怎么做了,这是set,也是map的特性----去重和排序

2.2迭代器

在这里插入图片描述
迭代器这部分没有什么好讲解的,迭代器设计初衷,就是为了是所有容器的遍历都是一样的,博主就带大家过一遍这个迭代器的使用
在这里插入图片描述
我们看到排序了又去重了,我们看看修改数据会发生什么??
在这里插入图片描述

我们看到不允许进行修改,原因是修改会破坏二叉搜索树的结构,如果想要修改一个数据可以先删除,在插入想要修改后的数据。

为什么不可以进行修改呢,是怎么控制的?
在这里插入图片描述

我们发现他的迭代器都是使用const修饰的,所以可以控制数据不会被修改,其他的迭代器都是和之前一眼固定用法,我也不做过多的演示了,大家感兴趣自己下去实验一下。

2.3修改函数接口

在这里插入图片描述
插入函数insert:
在这里插入图片描述
这个pair一会将set的最后一个函数的时候在细讲!!

	set<int> s;s.insert(4);s.insert(3);s.insert(6);s.insert(2);s.insert(3);set<int>::iterator it = s.begin();for (auto e : s){cout << *it << " ";it++;}

在这里插入图片描述
这和我们构造函数看到的效果是一样的。

删除函数erase:
在这里插入图片描述

	cout << endl;s.erase(1);s.erase(2);s.erase(3);it = s.begin();for (auto e : s){cout << *it << " ";it++;}

在这里插入图片描述
这个删除的效果就很简单,有就删除,没有就不做任何处理

后面几个就不做介绍,clear和swap大家肯定都会,最后两个等到C++11章节在细说

2.4操作函数

在这里插入图片描述

这两个在set里面含义是一样,都是获取key的值,在map里面就不一样

在这里插入图片描述

这三个函数大家最熟只不过了,也不做演示了。

在这里插入图片描述

这几个函数我要做一下特别介绍,因为这才是set和其他STL容器的不同.


find:
在这里插入图片描述

找到了就返回迭代器位置,没找到就返回end的位置,左闭右开,所以是最后一个元素后面的一个位置

具体使用:
在这里插入图片描述

我们看到set自带的和库里面的查找函数都可以完成查找的功能,为什么set还要单独在设计一个查找函数的,原因是,set的查找函数的左右找,不是像库里面的一个个的遍历查找,所以自带的复杂度可以达到O(logn),而库里面的只有O(n)。


count:
在这里插入图片描述
这个函数对于set其他意义不大,他是统计数据出现的次数,而set里面的数据没有重复的,所以只有1个,在set中这个函数可以判断一个数据在不在
在这里插入图片描述
那这个函数的意义在哪呢,我们讲完剩下来的三个函数在具体说。


lower_bound和upper_bound:
在这里插入图片描述
正常情况这两个函数是同时使用的,一个用来找左边界,一个用来找右边界
在这里插入图片描述

lower_bound是找到大于等于val值的迭代器
upper_bound是找到大于val值的迭代器

原因是他要配合插入删除来使用,因为插入和删除都可以使用迭代器来操作,而且是左闭右开的,所以upper_bound是返回比val大的迭代器位置返回。


equal_range:
在这里插入图片描述

在这里插入图片描述

pair其实是一个类模板结构,这个类里面右两个变量,把两个值放在一个结构里面了,一会再讲map的时候会讲为什么会这样设计。

具体使用:
在这里插入图片描述

我们返回的是返回的是一个pair的结构,所以第一个数是返回的是val的迭代器,而第二个返回的是最后依次出现val值后一位值的迭代器,再set当中体现不出来


multiset:
上面的count和equal_range其实是为multiset设计的,这个STL有什么功能呢,相比较于set这个函数不去重

在这里插入图片描述

通过上面的图我们发现count可以统计val出现了几次,equal_range的first返回第一次val出现的迭代器,second返回最后一个val出现的下一个位置,其实是为了插入和删除的,这个大家要明白.

注意: multiset的其他使用和set是一样的,我们大部分情况都是使用set这个容器,其次set的主要功能是判断在不在。

三、map

在这里插入图片描述
学习了set我们再学习map其实难度会好很多,我们的map是一个key_value模型,两者是绑定的。我们的map和set一样可以去重,他的key只能由一个,但是value不是唯一。

接下来就带大家看看由哪些接口函数吧
在这里插入图片描述

接下来博主会介绍圈主的部分,五个操作函数的使用和set是一样的,传key的值就可以了,这个大家下来看看文档就可以理解了

3.1插入和删除函数

之前再set插入的时候返回值就是pair,为什么要设计程这样,我们知道,key_value模型,是讲着两个值进行绑定在一起,所以再插入或者删除的是都是一起操作的,既然这样,我们把这两个值放到一个结构体里面,通过控制这个结构体来控制这两个值,所以pair就是相当于这样的一个作用,我们来看一下插入函数

insert:
在这里插入图片描述
我们插入的时候也是插入一个结构体对象的引用,我们来具体来看看怎么使用:

	map<int, string> m1;pair<int, string> p(1, "数字1");//最基本的插入方式m1.insert(p);m1.insert(make_pair(2, "数字2"));//make_pair调用pairm1.insert({ 3, "数字3" });//c++11的多参数隐式类型转换m1.insert({ 3, "数字3" });//c++11的多参数隐式类型转换m1.insert({ 3, "数字3" });//c++11的多参数隐式类型转换m1.insert({ 4, "数字3" });//c++11的多参数隐式类型转换

在这里插入图片描述
在这里插入图片描述
我们看到map也实现了去重,当key有相同的就不插入,不覆盖,插入过程值比较key,value相同无所谓,make_pair也是我们平时使用最多的,而且也不能对插入后的key进行修改


其次我们看到插入也会返回一个pair,一个是插入位置的迭代器,一个是插入是否成功。
在这里插入图片描述
这个大家一定要先理解,因为一会讲解的[]就和这个有关,先给大家铺垫一个比较好理解的,才能更好的接受不太好理解的

erase:
在这里插入图片描述

只需要传key的值就可以了。博主就不做具体演示了。

3.2operator[]函数

接下来带大家来看看之前的题目,大家还记得统计水果次数的功能吗??大家可以看看之前写的二叉搜索树,今天我们有map就很简单我们来看看代码:

	//第一种map<string, int> countMap;string arr[] = { "苹果","香蕉","苹果","梨子","苹果","香蕉","梨子" };for (auto e : arr){auto it = countMap.find(e);if (it == countMap.end()){countMap.insert(make_pair(e, 1));}else{it->second++;}}map<string, int>::iterator it = countMap.begin();for (auto e : countMap){cout << it->first << " " << it->second << endl;it++;}//第二种cout << endl;map<string, int> countMap1;string arr1[] = { "苹果","香蕉","苹果","梨子","苹果","香蕉","梨子" };for (auto e : arr1){countMap1[e]++;}map<string, int>::iterator it1 = countMap1.begin();for (auto e : countMap1){cout << it1->first << " " << it1->second << endl;it1++;}

在这里插入图片描述
通过第一种的思路,我们第二种看着很简单,但是里面的核心思路还是和第一种一样,内部是插入操作,我们来通过文档看看这个[]实现的原理是什么??

我们来看文档:
在这里插入图片描述

大家还记得我们插入操作的时候研究insert返回值的的案例吗。和这个一模一样。
在这里插入图片描述
此时大家应该明白[]的工作原理了吧,其实就要搞懂调用关系以及pair的特性,这个再模拟实现的时候会更清楚的,大家先理解着。


接下来就是multimap这个容器,他这个容器和map几乎一模一样,他不可以去重,所以[]这个函数他就没有,其余的使用和毛一样,博主就不做具体介绍了,接下来博主来使用set和map带啊大家来解决原来比较难解决的题目

注意:map是用来统计次数的,也可以判断数据在不在的,map的使用度更广泛

四、set和map的应用

4.1349. 两个数组的交集

这个题目也是很经典的,接下来我讲带大家怎么来解决这个问题。
在这里插入图片描述
所以这题我们不需要统计次数,所以使用set就可以了,set可以去重也可以排序,所以符合上图的分析思路,来看代码:

class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {vector<int>v;set<int> s1(nums1.begin(),nums1.end());set<int> s2(nums2.begin(),nums2.end());auto it1=s1.begin();auto it2=s2.begin();while(it1!=s1.end()&&it2!=s2.end()){if(*it1<*it2){it1++;}else if(*it1>*it2){it2++;}else{v.push_back(*it1);it1++;it2++;}}return v;}
};

4.2有效的括号

这个题目大家非常熟悉不过了,因为需要把括号两边进行绑定,所以需要使用map去操作,这样题目说有更多的括号都不用担心,再前面进行修改就好了。

class Solution {
public:bool isValid(string s) {stack<char> st;map<char,char> m;m['(']=')';m['{']='}';m['[']=']';for(auto e:s){if(m.count(e)){st.push(e);}else{if(st.empty()){return false;}else{char top=st.top();st.pop();if(m[top]!=e){return false;}}}}return st.empty();}
};

通过上面两个应用大家对set和map应该了解了。接下来我将给大家讲解AVL树了,难度有所提升,希望大家可以好好理解,加深理解,今天讲的对后面的模拟实现会很有帮助的,我们下篇再见

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

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

相关文章

【Python 实战】---- 实现批量图片的切割

1. 需求场景 在实际开发中&#xff0c;我们会遇到一种很无聊&#xff0c;但是又必须实现的需求&#xff0c;就是比如协议、大量的宣传页面、大量的静态介绍页面、或者大量静态页面&#xff0c;但是页面高度很高&#xff0c;甚至高度可能会达到50000px&#xff0c;但是为了渲染…

vue知识点————插槽 slot

slot 插槽 在父组件中引用的子组件 在父组件中写入百度 可在子组件slot插槽中展示出 父组件 <template><div id"app"><child url"https://www.baidu.com">百度</child></div> </template><script> import chil…

解决golang无法下载依赖的奇葩问题

最近刚开始学习go&#xff0c;看了几个开源项目&#xff0c;遂下载好朋友的go开源项目&#xff0c;想着coding first&#xff0c;我得先跑起来&#xff0c;结果居然卡在依赖上。就像下图&#xff1a; 真的是头疼&#xff0c;反复执行 go mod tidy&#xff0c;发现本地库中也能下…

教你制作作业查询系统

嗨&#xff0c;各位老师们&#xff0c;今天我要给你们介绍一个超级方便的工具——易查分&#xff01;你知道吗&#xff0c;利用易查分&#xff0c;我们可以轻松制作一个便捷高效的作业查询系统哦&#xff01; 是不是想有个自己的分班or成绩查询页面&#xff1f;博主给老师们争取…

【操作系统】进程的状态

进程的五种状态 创建&#xff0c;就绪&#xff08;等待分配处理机CPU资源&#xff09;&#xff0c;执行&#xff0c;阻塞&#xff08;叫阻塞因为相对CPU来说它很慢&#xff0c;等待除CPU以外的资源&#xff0c;如I/O&#xff09;&#xff0c;终止。 创建好的进程放入就绪队列等…

前端--HTML

文章目录 HTML结构快速生成代码框架HTML常见标签 表格标签 编写简历信息 填写简历信息 Emmet 快捷键 HTML 特殊字符 一、HTML结构 1.认识HTML标签 HTML 代码是由 "标签" 构成的. 形如: <body>hello</body> 标签名 (body) 放到 < > 中 大部分标…

centos安装flink,通过windows访问webui

1. 安装flink 1.1. flink的下载 通过flink官网下载flink安装包 https://flink.apache.org/ 下载安装包 1.2 flink在centos上的安装 将下载好的flink-1.17.1-bin-scala_2.12.tgz安装包放到centos目录下 解压文件&#xff1a; [rootlocalhost ~]# tar -zxvf flink-1.17.…

JS中应该注意的点

本帖子记录在使用前端时遇到的一些小点。 1.html()和text()和val()的使用及区别 1.1 val() val&#xff08;&#xff09;是对于单标签元素的值&#xff0c;其中一个很重要的特性是value"" Value:<input id"input" type"text" value"LO…

熵 | 无线通信知识

文章目录 一、信息论&#xff08;熵、联合熵、条件熵&#xff09;二、Bernoulli熵三、联合熵和条件熵四、互信息五、相对熵(KL距离)六、微分熵七、最大熵分布常需要的不等式公式 一、信息论&#xff08;熵、联合熵、条件熵&#xff09; 熵定义&#xff1a; H ( X ) E [ − l …

VRTK4⭐一.VRTK4和VRTK的区别 , 及VRTK4简介

文章目录 &#x1f7e5; VRTK4和VRTK的区别1️⃣ 版本区别2️⃣安装方式区别 &#x1f7e7; 安装VRTK41️⃣ AssetStore网址2️⃣安装不同功能的包 &#x1f7e9;Tilia的独立功能包介绍及配置方法&#x1f381;Tilia.CameraRigs.SpatialSimulator.Unity [重要]&#x1f381;Til…

Java“牵手”1688商品列表页数据采集+商品价格数据排序,商品销量排序数据,1688API接口采集方法

1688平台是阿里巴巴旗下的综合性B2B电子商务平台。该平台目前属于阿里巴巴集团旗下子公司&#xff0c;以批发和采购业务为核心&#xff0c;通过专业化运营、全面优化企业电子商务的业务模式&#xff0c;主要分为垂直行业市场及特色服务频道&#xff0c;垂直行业市场主要针对行业…