【C++】来学习使用set和map吧

在这里插入图片描述
各位大佬好,我是落羽!一个坚持不断学习进步的大学生。
如果您觉得我的文章有所帮助,欢迎多多互三分享交流,一起学习进步!

也欢迎关注我的blog主页: 落羽的落羽

文章目录

  • 一、set和map是什么
  • 二、set系列
    • 1. set
    • 2. multiset
  • 三、map系列
    • 1. map
    • 2. multimap

一、set和map是什么

我们之前已经学习过了STL库中的部分容器,如string、vector、list、deque,这些容器统称之为序列式容器,因为它们的逻辑结构都是线性的,存储元素之间一般没有紧密的联系关系,即使交换元素位置,数据结构仍是线性的。这些序列式容器的元素是按照他们在容器中存储的位置来顺序保存和访问的。

关联式容器的逻辑结构则是非线性的结构,元素位置之间有紧密的关联关系,交换位置则存储结构会破坏。关联式容器有map/set系列和unordered_map/unorderer_set系列。

今天我们学习的set和map,底层是红黑树,红黑树是一棵平衡二叉搜索树。set是key搜索场景的结构,而map是key/value搜索场景的结构。

二、set系列

使用set系列的set、multiset,都需要#include <set>

1. set

set是不允许key值重复出现的平衡二叉搜索树。

在这里插入图片描述

  • set的模板参数T,就是key的类型。
  • set默认要求key值是小于比较,也就是这棵树中左子树key < 结点key < 右子树key,因为第二个模板参数默认传的是less<T>。我们也可以自己传greater<T>使之变成大于比较,即这棵树中左子树key > 结点key > 右子树key。
  • 由于set底层是红黑树,增删查效率是O(logN),效率很高,中序遍历默认是升序的。

set的几种构造方式:
在这里插入图片描述

set也有迭代器,也有begin和end一系列接口。在这里插入图片描述
set的begin()和end()是它的中序遍历序列的开头和结尾,begin是中序第一个结点,end是中序的最后一个结点的下一个位置。后面的容器也是一样,begin和end都是中序遍历的位置。不难想象,begin()返回的是最小key值结点的迭代器
set支持正向和反向迭代器,也支持范围for,迭代器++和范围for都是按照树的中序顺序进行遍历。但是set的iteritor和const_iteritor都不支持迭代器修改key,会破坏底层搜索树的结构。

在这里插入图片描述

set类中当然还有增删查等相关功能:

  • find:查找key为传参val的位置,若存在则返回这个位置的迭代器,若不存在则返回end()在这里插入图片描述

  • count:记录set中key为传参的结点个数在这里插入图片描述
    这个函数的返回值是size_t类型,是key值为val的个数,但是由于set中不允许有重复key值,所以set类对象这个函数的返回值只能是0或1,也就可以依据是0或1判断某个key是否存在。换句话说,count也可以有查找判断key是否存在的功能。

  • insert:插入新的key在这里插入图片描述 insert可以插入单个数据、一段迭代器区间、一段{ }列表。但由于set不允许有重复key值,所以插入内容中出现了重复key值则不会插入。这个过程实际是先进行了一次查找操作,在原set中找不到想新插入的key,才能进行插入

  • erase:删除结点在这里插入图片描述
    erase可以传一个迭代器删除这个迭代器的结点,可以传一段迭代器区间整体删除。也可以传一个key值删除这个key值的结点,找不到这个key结点则不删除,这种版本的erase返回值是size_t,和count道理一样,返回值代表删除的结点个数,1代表删除了一个结点,0代表没有删除结点,也可以用于判断删除是否成功。

演示:
在这里插入图片描述

除此之外,set还有两个接口lower_bound、upper_bound:
在这里插入图片描述

在这里插入图片描述

它们通常一起使用,lower_bound返回set中的第一个key值>=val值的结点的迭代器,upper_bound返回set中的第一个key值>val值的结点的迭代器它们的作用是找一段值的区间
比如一个set中结点为{10, 20, 30, 40, 50, 60, 70, 80, 90}auto it1 = lower_bound(30);
则it1是结点30的迭代器,auto it2 = upper_bound(70);,则it2是结点70的迭代器。也就是说,it1和it2两个迭代器包含了30、40、50、60、70这段结点区间。
这两个函数的传参可以不是set中已存在的key值,比如上面的例子,传auto it1 = lower_bound(35);则it1是结点40的迭代器,auto it2 = upper_bound(75);,则it2是结点80的迭代器。
若它们找不到比val大的key结点,则返回end()。

演示:
在这里插入图片描述

2. multiset

multiset也是set系列的一种,相比于set,它支持key值的冗余,也就是可以存在重复的key值。相同的key可能在根结点key的左边或右边。它的使用与set大体类似,但find、insert、erase、count等与set的有所差异:

  • find:multiset的key中可能有多个为val的结点。multiset的find是按照中序序列查找第一个key为val的结点,返回它的迭代器。
  • insert:multiset支持存在重复的key,因此插入已存在key值的新结点也能成功。
  • erase:multiset的这种erase版本size_type erase (const value_type& val);会删除所有key值为val的结点,返回值是删除的结点的个数。因为multiset中可能有重复key值,所以返回值可能是任何非负整数。
  • count:和set一样,也是记录返回key值为传参val的结点个数。因为multiset中可能有重复key值,所以返回值可能是任何非负整数。

只要理解了multiset和set的差异只在于muliset支持key重复存在,它们的接口的差异都很好理解了。

演示:在这里插入图片描述

multiset也有lower_bound和upper_bound操作,和set道理一样。

multiset中还有一个equal_range,是查找key值为传参val的结点的区间。因为multiset中若有重复的key结点,则它们在中序序列中一定是连续的。equal_range就返回这一段迭代器区间。注意到它的返回类型是pair<iteritor, iteritor>,这就是两个迭代器的组合代表一段区间,关于pair具体下面再介绍。在这里插入图片描述

三、map系列

使用map系列的map、multimap,都需要#include <map>

1. map

set系列底层是key结构的红黑树,而map系列底层是key/value结构的红黑树。
map不允许key值重复出现的平衡二叉搜索树。

在这里插入图片描述

其中,Key是key的类型,T是value的类型。Compar默认传less要求支持小于比较。map的增删查改效率是O(N),迭代器也是走的中序遍历,按照key的有序顺序进行遍历。
而在map的结点中,它的key和value其实是被封装成一个叫pair的结构体来存储的:

在这里插入图片描述

pair的结构其实很简单,就是两个类型的两个成员封装在一起,T1 firstT2 second。在map的结点中的pair,T1为key的类型,T2为value的类型,first就是key,second就是value。map的结点中,使用pair<Key, T>存储键值对数据。当然,pair类型中还有一些构造函数、拷贝构造函数,不多赘述。

map的构造、迭代器、其他操作大体和set都是相似的,区别只在于map可以修改value值,不能修改key值。查和删的操作只关注key,所以map的查和删和set一样。增的操作不仅要增key,还要增value:

在这里插入图片描述
第一个版本的insert返回类型是pair<iterator, bool>如果key已在map中,则插入失败,返回的pair的first是已存在key所在节点的迭代器,second是false;如果key不在map中,插入成功,返回的pair的first是新插入key的结点迭代器,second是true。也就是说,无论key插入失败成功,insert的返回值的first都是key结点的迭代器,意味着insert也能充当查找的功能,下面[ ]的重载就是利用了这一点。
insert要求的参数是一个pair,这里其实就很灵活了。可以构造对象再传参、匿名对象传参、隐式类型转换传参:
在这里插入图片描述

相比set,map还可以修改value的功能。一种方法是通过迭代器,map的迭代器相当于指向pair的指针,利用迭代器->second = x;来完成修改。
另一种方法,map重载了[]操作符,但是用法很特殊:map的[ ]中不是传寻常的下标,而是传key值,若这个key值在map中已存在,则返回它对应的value的引用;若这个key值不存在,则将这个key新插入进去,它的value则使用它的缺省值或调它的类型的默认构造,也返回value的引用。

value若是自定义类型,就有它的默认构造;内置类型也有默认构造,如int默认构造为0,指针默认构造为nullptr。

不难看出,[ ]有查找+插入的功能,同时因为返回value的引用,也具备了修改的功能。map的[ ]重载是一个非常重要的多功能接口,它的内部实现是这样的,利用刚才说的insert的特点:

T& operator[](const Key& key)
{pair<iterator, bool> ret = insert({key, T()});//it指向了key值的结点,不论这个key是已存在的还是新插入的iterator it = ret.first;//it相当于指向了pair,it的second就是value了return it->second;
}

map的[ ]在一些特定场景下使用是很爽的,比如这样一个例子:统计字母出现个数。
不使用[ ]可能要这么做:

vector<char> v = { 'a','b','c','b','a','c','a','a','b' };//构建一个map<char,int>,char代表字母,int代表它的出现次数
map<char, int> countMap;for (auto e : v)
{//查找字母在不在map中auto ret = countMap.find(e);//不在,说明这个字母是第一次出现,插入{字母,1}if (ret == countMap.end()){countMap.insert({ e,1 });}//这个字母存在,则它的出现次数+1else {ret->second++;}
}for (auto e : countMap)
{cout << e.first << ":" << e.second << "次" << endl;
}
cout << endl;

在这里插入图片描述

但使用[ ],就更简洁了:

vector<char> v = { 'a','b','c','b','a','c','a','a','b' };//构建一个map<char,int>,char代表字母,int代表它的出现次数
map<char, int> countMap;for (auto e : v)
{//字母不在,说明这个字母第一次出现,则插入,int默认构造成0,++一下就成1了//字母在,也返回value的引用,也会++一次countMap[e]++;
}for (auto e : countMap)
{cout << e.first << ":" << e.second << "次" << endl;
}
cout << endl;

在这里插入图片描述
没有问题!

2. multimap

multimap就是支持key重复出现的map,同一key值的不同结点的value也可以不一样。multimap的增删查改相对于map也有一些不同,但是大概规律和multiset相对于set一样,比如find返回多个key值结点的中序遍历第一个。除此之外就是multimap不支持map的[ ]

本篇完,感谢阅读~

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

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

相关文章

h5st逆向分析

h5st最新5.1版本逆向分析 申明定位h5st生成的位置动态插桩,事半功倍日志分析,十分钟还原算法逻辑申明 本文仅用来记录学习过程以免日后忘了,如有侵权请联系删除。 定位h5st生成的位置 通过关键字“sign”搜索,可以定位到window.PSign.sign(f)这个位置,f参数的值为{ &qu…

湖北理元理律师事务所企业债务优化路径:司法重整中的再生之道

一、企业债务危机的核心矛盾&#xff1a;生存与清偿的博弈 通过分析湖北理元理律师事务所经办的17件企业债务案件&#xff0c;发现共性难题&#xff1a; 债权人要求立即清偿 → 企业需持续经营造血 → 司法程序存在时间差 解决方案&#xff1a;构建“三重防火墙”机制 经…

链家Android面试题及参考答案

目录 请详细解释类加载的过程,包括每一步的具体实现。并说明Android中的dex分包技术及其在热更新中的应用 比较JVM和DVM的区别。在JVM中一个程序崩溃是否可能导致系统崩溃?DVM中呢? 请解释网络IP协议、TCP、UDP、HTTP、HTTPS、Socket的概念,并说明它们之间的区别 请深入…

LeetCode-多语言实现冒泡排序以及算法优化改进

目录 一、冒泡排序算法 二、应用场景/前提条件 &#x1f308; 优点 &#x1f4e2; 缺点 三、经典算法实现并优化改进 方法一&#xff1a;记录最后一次交换位置&#xff0c;下一轮只遍历到该位置 方法二&#xff1a;添加标志位跟踪是否发生交换&#xff0c;无交换则提前终…

JAVA毕业设计227—基于SpringBoot+hadoop+spark+Vue的大数据房屋维修系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于SpringBoothadoopsparkVue的大数据房屋维修系统(源代码数据库)227 一、系统介绍 本项目前后端分离&#xff0c;分为业主、维修人员、管理员三种角色 1、业主&#xff1a; 登…

MADlib —— 基于 SQL 的数据挖掘解决方案(9)—— 数据探索之概率统计

目录 一、概率 1. 概率的定义 2. 概率质量函数与概率密度函数 3. 条件概率 4. 期望值 二、MADlib 的概率相关函数 1. 函数语法 2. 示例 &#xff08;1&#xff09;求标准正态分布下&#xff0c;1 的概率密度函数 &#xff08;2&#xff09;求标准正态分布下&#xff…

耳蜗里的春天

早春的郑州飘着细雨&#xff0c;我牵着女儿小满的手走进市残疾人康复中心时&#xff0c;玻璃门内突然传来一阵清脆的笑声。穿天蓝色毛衣的小女孩戴着粉色耳蜗&#xff0c;正踮脚拍打着墙上的卡通贴画&#xff0c;银色的连接线在她耳后晃动&#xff0c;像一只折翼却仍在起舞的蝴…

OCR(光学字符识别)算法

OCR&#xff08;光学字符识别&#xff09;算法在景区护照阅读器中的应用是核心技术之一&#xff0c;它通过图像处理和机器学习快速提取护照信息&#xff0c;显著提升自动化水平。以下是其具体应用场景、技术实现及优化方向&#xff1a; 一、OCR在护照阅读器中的核心作用 关键信…

html打印合同模板

概述&#xff08;吐槽&#xff09;&#xff1a;记录一个html打印合同模板的功能&#xff0c;技术栈有点杂&#xff0c;千禧年出产老系统的数据库是sqlserver2008&#xff0c;原系统框架是c#&#xff0c;无法二开&#xff0c;因为原系统的合同生成功能出现bug&#xff0c;没有供…

DeepCritic: SFT+RL两阶段训练突破LLM自我监督!显著提升大模型的自我批判能力!!

摘要&#xff1a;随着大型语言模型&#xff08;LLMs&#xff09;的迅速发展&#xff0c;对其输出进行准确反馈和可扩展监督成为一个迫切且关键的问题。利用LLMs作为批评模型以实现自动化监督是一个有前景的解决方案。在本研究中&#xff0c;我们专注于研究并提升LLMs在数学批评…

【深度学习】深度学习中的张量:从多维数组到智能计算单元

✅ 一、n维数组&#xff08;张量&#xff0c;Tensor&#xff09; 1. 定义 张量&#xff08;Tensor&#xff09;是一个通用的n维数组数据结构。 它的维度&#xff08;维数&#xff09;决定了它的形状&#xff0c;例如&#xff1a; 维度名称举例说明0维标量&#xff08;scalar…

以太网MDI信号PCB EMC设计要点

1. PHY侧和RJ45连接器侧通用MDI布局建议 1. MDI差分对保持对称走线&#xff0c;走线上的焊盘封装应一致&#xff0c;焊盘放置位置也应对称。可以减少EMI测试中的模式转换。   2. MDI走线应保持阻抗匹配&#xff0c;从而减少信号线上的反射。   3. MDI走线下需有连续完整的接…

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…

pysnmp模块中 GET、SET、WALK操作详细分步解析

1. SNMP GET 操作详解 1.1 核心代码结构 from pysnmp.hlapi import *# 定义参数 community public # SNMPv2c 社区名 target_ip 192.168.1.1 # 目标设备 IP oid 1.3.6.1.2.1.1.1.0 # 要查询的 OID# 发起 GET 请求 error_indication, error_status, error_index, …

接收rabbitmq消息

以下是一个使用纯Java&#xff08;非Spring Boot&#xff09;接收RabbitMQ消息的完整实现&#xff0c;包含Maven依赖和持续监听消息的循环&#xff1a; 1. 首先添加Maven依赖 (pom.xml) <dependencies><!-- RabbitMQ Java Client --><dependency><group…

SQL进阶之旅 Day 23:事务隔离级别与性能优化

【SQL进阶之旅 Day 23】事务隔离级别与性能优化 文章简述 在数据库系统中&#xff0c;事务是确保数据一致性和完整性的核心机制。随着业务复杂度的提升&#xff0c;如何合理设置事务隔离级别以平衡并发性能与数据一致性成为开发人员必须掌握的关键技能。本文深入解析事务隔离级…

六.原型模式

一.原型模式的定义 原型模式是一种创建型设计模式&#xff0c;通过复制现有对象&#xff08;原型&#xff09;生成新对象&#xff0c;避免重复初始化成本。需了解以下关键概念&#xff1a; ‌浅拷贝‌&#xff1a;复制基本类型字段&#xff0c;引用类型字段共享内存地址&#…

【笔记】LoRA 理论与实现|大模型轻量级微调

论文链接&#xff1a;LoRA: Low-Rank Adaptation of Large Language Models 官方实现&#xff1a;microsoft/LoRA 非官方实现&#xff1a;huggingface/peft、huggingface/diffusers 这篇文章要介绍的是一种大模型/扩散模型的微调方法&#xff0c;叫做低秩适应&#xff08;也就是…

Cilium动手实验室: 精通之旅---15.Isovalent Enterprise for Cilium: Network Policies

Cilium动手实验室: 精通之旅---15.Isovalent Enterprise for Cilium: Network Policies 1. 环境信息2. 测试环境部署3. 默认规则3.1 测试默认规则3.2 小测验 4. 网络策略可视化4.1 通过可视化创建策略4.2 小测试 5. 测试策略5.1 应用策略5.2 流量观测5.3 Hubble观测5.4 小测试 …

opencv RGB图像转灰度图

这段代码的作用是将一个 3通道的 RGB 图像&#xff08;CV_8UC3&#xff09;转换为灰度图像&#xff08;CV_8UC1&#xff09;&#xff0c;并使用 OpenCV 的 parallel_for_ 对图像处理进行并行加速。 &#x1f50d; 一、函数功能总结 if (CV_8UC3 img.type()) {// 创建灰度图 d…