C++笔记---set和map

1. 序列式容器与关联式容器

前面我们已经接触过STL中的部分容器如:string、vector、list、deque、array、forward_list等,这些容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间一般没有紧密的关联关系,比如交换⼀下,他依旧是序列式容器。

顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的。

关联式容器也是用来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是非线性结构,两个位置有紧密的关联关系,交换一下,他的存储结构就被破坏了。

顺序容器中的元素是按关键字来保存和访问的。

关联式容器有map/set系列和unordered_map/unordered_set系列。

本章节讲解的map和set底层是红黑树,红黑树是一颗平衡二叉搜索树。

set/multiset是key搜索场景的结构, map/multimap是key/value搜索场景的结构。

set/map不支持相同的值插入,multiset/multimap支持相同的值插入。

2. pair类 

在正式介绍set和map之前,我们需要先了解一下pair类。

这个类也是一个类模板,顾名思义,它的作用就是存储两个数据,也即将两个数据绑定到一起。

在需要返回两个数据的场景下,我们就可以将两个数据存到pair中进行返回。

pair的原型如下:

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){}// 支持隐式类型转换template<class U, class V>pair(const pair<U, V>& pr) : first(pr.first), second(pr.second){}
};// C++11之间常用的构造pair的函数
template <class T1, class T2>
inline pair<T1, T2> make_pair(T1 x, T2 y)
{return (pair<T1, T2>(x, y));
}

3. set的介绍

参考文档:set - C++ Reference,关于set的使用,将其当作key搜索场景的红黑树来使用即可。

set的原型:

template < class T,                        // set::key_type/value_typeclass Compare = less<T>,        // set::key_compare/value_compareclass Alloc = allocator<T>      // set::allocator_type> class set;

类型参数分别为:key的类型,比较器(通过仿函数实现,默认为小于比较,中序遍历得到升序序列),内存池。

一般来说,后两个参数有缺省值,的使用频率较低,我们在日常使用的过程中只需要传入第一个参数即可。

3.1 常用接口

STL的容器都是大同小异,这里只列出需要注意的。

3.1.1 构造函数
set();默认构造
template <class InputIterator>
set(InputIterator first, InputIterator last);
迭代器区间构造
set(const set& x);拷贝构造

在C++11之后还支持用列表构造:

// initializer list (5) initializer 列表构造
set (initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());eg:
set<int> mySet1({1, 2, 3, 4});
set<int> mySet2 = {1, 2, 3, 4};

在原文档中,前两个构造函数的参数列表还包括比较器和内存池:

但是经过我自己的测试发现,如果在定义set的时候传入比较器或内存池,这个定义语句会被编译器识别成函数的声明:

也就是说,比较器和内存池依然只能在类型参数列表中传入。

 3.1.2 迭代器

这里就不列表了,set的迭代器是双向迭代器,函数还是那几个函数。

正向迭代器的是按照key值从小到大进行遍历。

除此之外,在set中无论是iterator还是const_iterator都不支持通过解引用修改set中的数据,因为这样会破坏红黑树的底层结构。

3.1.3 增删
(1)pair<iterator, bool> insert(const value_type& val);
(2)iterator insert(iterator position, const value_type& val);
(3)template <class InputIterator>
   void insert(InputIterator first, InputIterator last);

(1)按值插入

(2)指定位置插入

(3)将容器的迭代器区间内的值插入

(1)void erase(iterator position);
(2)size_type erase(const value_type& val);
(3)void erase(iterator first, iterator last);

(1)删除指定位置的值

(2)删除指定的值

(3)删除一个迭代器区间

insert函数(1)的返回值是一个pair:

插入成功时:iterator为新插入数据的迭代器,bool为true

插入失败时:iterator为已有的相同值的迭代器,bool为false

 insert函数(2)的第一个参数实质上只是一个插入建议,由于set的特殊的红黑树的底层结构,该插入建议可能不会被采纳。

 3.1.4 查找
iterator find (const value_type& val) const;查找某个值
size_type count (const value_type& val) const;查找某个值在set中有几个

set不支持相同的值进行插入,所以count的结果不是1就是0。

这样看来count似乎有点鸡肋,或者说与名称不符,但set中的count实际上是为了与multiset统一而存在的。

但count也并非一无是处,如果只想确定某个值存不存在的话,count就稍微比find方便一点:

if(mySet.find(24) != mySet.end())
{// ......
}if(mySet.count(24))
{// ......
}

3.2 multiset

基本与set相同,但是支持插入相同的数据,由此而引发的变化还有:

1. insert一定成功,插入函数(1)的返回值不再是pair而只有iterator。

2. count返回数据在set中的个数。

3. 如果有多个相同的值,无论是删除还是查找,都是对中序遍历的第一个进行操作。

 4. map的介绍

参考文档:map - C++ Reference,关于map的使用,将其当作key/value搜索场景的红黑树来使用即可。

map的原型:

template < class Key,                                     // map::key_typeclass T,                                       // map::mapped_typeclass Compare = less<Key>,                     // map::key_compareclass Alloc = allocator<pair<const Key,T> >    // map::allocator_type> class map;

类型参数分别为:key的类型,value的类型,比较器(通过仿函数实现,默认为小于比较,中序遍历得到升序序列),内存池。

除此之外,pair在map中起到了将key和value绑定到一起的作用,所以在map的结点中存的数据实际上是pair,而没有单独存储key和value。

typedef pair<const Key, T> value_type;

同样,大多数情况下只需要传入前两个参数即可。

4.1 常用接口

同样,此处只列出较为重要或与其他容器有所不同的。

4.1.1 构造函数
map();默认构造
template <class InputIterator>
map (InputIterator first, InputIterator last);
迭代器区间构造
map (const map& x);拷贝构造

在C++11之后支持列表构造:

// initializer list (5) initializer 列表构造
map (initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());eg:
map<string, int> myMap1({{"张三", 18}, {"李四", 21}, {"王五", 35}});
map<string, int> myMap2 = {{"张三", 18}, {"李四", 21}, {"王五", 35}};

内层大括号会通过pair的列表构造隐式类型转换为pair<string, int>类型。 

关于参考文档中给出的函数原型,依然存在着和set相同的问题。

 4.1.2 迭代器

函数还是那些函数,迭代器还是双向迭代器。

但与set不同的是,map的迭代器支持对value进行修改,而依然不支持对key进行修改。

由于map结点中存的是pair<key, value>,所以按照逻辑来说,map的迭代器解引用得到的就是pair<key, value>。

在pair中,key对应的是first,value对应的是second:

map<string, int> myMap(...);
map<string, int>::iterator it = myMap.begin();
while(it != myMap.end())
{cout << "key:" << (*it).first << " value:" << *(it).second << endl;cout << "key:" << it->first << " value:" << it->second << endl;
}
4.1.3 增删
(1)pair<iterator, bool> insert(const value_type& val);
(2)iterator insert(iterator position, const value_type& val);
(3)template <class InputIterator>
   void insert(InputIterator first, InputIterator last);

(1)按值插入

(2)指定位置插入

(3)将容器的迭代器区间内的值插入

(1)void erase(iterator position);
(2)size_type erase(const key_type& k);
(3)void erase(iterator first, iterator last);

(1)删除指定位置的值

(2)删除指定的值

(3)删除一个迭代器区间

函数原型与set完全一样,除了erase函数(2),只需要key即可找到对应的数据进行删除。

但是要切记,这里的value_type是pair。

insert函数(1)的返回值逻辑也与set相同,但是只要key相同就不支持继续插入了。

4.1.4 查找
iterator find (const key_type& k);
const_iterator find (const key_type& k) const;
按键值key查找
size_type count (const key_type& k) const;查找某个键值key在set中有几个

 同样这里的count函数的返回值也只能是1或0。

4.1.5 operator[]

没错,map重载了"[]"。

但是,按理来说,只有支持随机迭代器的容器才可以重载"[]",而map不是双向迭代器吗?

看了函数原型你就明白了:

mapped_type& operator[] (const key_type& k);

所以,这个"[]"的功能是根据key来返回value的引用,而与迭代器没有关系。

但这个函数并不简单:

当key存在时,返回其对应的value的引用。

当key不存在时,在map中插入key,并给value默认值,然后返回value的引用。

所以map中的"[]"可以说是"查找,修改,插入"三位一体。

这是由于operator[]的内部实现是基于insert函数完成的:

// operator[]的内部实现
mapped_type& operator[] (const key_type& k)
{// 1、如果k不在map中,insert会插⼊k和mapped_type默认值,同时[]返回结点中存储//mapped_type值的引⽤,那么我们可以通过引⽤修改返映射值。所以[]具备了插⼊+修改功能// 2、如果k在map中,insert会插⼊失败,但是insert返回pair对象的first是指向key结点的//迭代器,返回值同时[]返回结点中存储mapped_type值的引⽤,所以[]具备了查找+修改的功能pair<iterator, bool> ret = insert({ k, mapped_type() });iterator it = ret.first;return it->second;
}

 4.2 multimap

基本与map相同,但是支持插入相同的数据,由此而引发的变化还有:

1. insert一定成功,插入函数(1)的返回值不再是pair而只有iterator。

2. count返回数据在map中的个数。

3. 如果有多个相同的值,无论是删除还是查找,都是对中序遍历的第一个进行操作。

4. 不再支持operator[],因为同一个key存在多组值。

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

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

相关文章

灾难级漏洞:阿里云盘可看别人隐私照?2亿用户或面临隐私泄露隐患

此次事件将阿里云盘的数据安全问题推至风口浪尖&#xff0c;对其品牌信誉和市场地位构成严峻挑战。 转载&#xff1a;科技新知 原创 作者丨江蓠 编辑丨蕨影 阿里云盘惊现灾难级别bug&#xff01; 9月14日晚&#xff0c;多名网友爆料称&#xff0c;可以在阿里云盘的相册中看到其…

三线城市的女玩家们不想“谈恋爱”,小游戏掘金新蓝海

女性玩家的游戏选项只有乙游吗&#xff1f; 在7月举办的微信小游戏开发者大会上&#xff0c;微信小游戏团队公布了一系列最新运营数据。数据显示&#xff0c;微信小游戏的用户规模已突破十亿大关。从用户画像来看&#xff0c;其年龄层主要集中在24至40岁之间&#xff0c;且三线…

一文读懂HPA弹性扩展自定义指标和缩放策略

一文读懂HPA弹性扩展自定义指标和缩放策略 目录 1 概念 1.1 什么是HPA1.2 HPA 的自定义指标&#xff08;Custom Metrics&#xff09;与扩展1.3 基于多指标的 HPA 1.3.1 工作原理1.3.2 例子&#xff1a;基于 CPU、内存和 QPS 的 HPA 配置 1.4 HPA 的扩缩容行为&#xff08;Beh…

集合根据上下级关系转树结构

1、创建实体对象 public class TreeNode {private String id;private String pid;private String name;private List<TreeNode> children;public TreeNode(String id,String pid,String name){this.id id;this.pid pid;this.name name;}public String getId() {retur…

VBA日历进度

hi&#xff0c;大家好&#xff01; 经过两次台风的洗礼之后&#xff0c;我们这里终于开始降温了&#xff0c;终于感觉到秋天的存在了&#xff01;时间也在一天天的过去&#xff0c;马上要十一假期了&#xff0c;十一过了&#xff0c;就可以算着过年了&#xff0c;让今天就让我…

OpenAI o1的真正前世竟来自字节?ReFT技术超越传统的数学微调能力,让GPT实现进化

导语&#xff1a; 随着ChatGPT-o1的发布&#xff0c;大型语言模型在复杂推理上取得进展&#xff0c;但传统监督式微调&#xff08;SFT&#xff09;仍存在局限。字节跳动研究院提出的增强微调&#xff08;ReFT&#xff09;技术结合了SFT和PPO算法&#xff0c;旨在提升模型泛化能…

HCIP考试范围包含哪些内容?HCIP备考指南分享

在数字化浪潮汹涌的今天&#xff0c;网络技术已成为支撑现代社会高效运转的不可或缺之力。Huawei Certified ICT Professional(HCIP)认证&#xff0c;作为这一领域中的精英标识&#xff0c;正吸引着无数技术爱好者的目光。那么&#xff0c;那么要考取这一认证需要掌握哪些考试内…

Github上开源了一款AI虚拟试衣,看看效果

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 前几天我们聊过关于虚拟换装的话题&#xf…

Android RecyclerView 实现 GridView ,并实现点击效果及方向位置的显示

效果图 一、引入 implementation com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30 二、使用步骤 1.Adapter public class UnAdapter extends BaseQuickAdapter<UnBean.ResultBean, BaseViewHolder> {private int selectedPosition RecyclerView.NO_POSITIO…

CVE-2024-1112 Resource Hacker 缓冲区溢出分析

漏洞简述 CVE-2024-1112 是 Resource Hacker 软件的一个缓冲区溢出漏洞。该漏洞存在于版本 3.6.0.92 中。由于软件在处理命令行中的文件路径时未对文件字符串长度进行限制&#xff0c;过长的字符串参数导致内存被过度写入&#xff0c;从而引发缓冲区溢出。 漏洞复现 构造长度…

基于相关性分析和梯度提升的睡眠质量影响因素研究

1.项目背景 注意该数据为人工合成数据&#xff0c;结论与认知可能不符&#xff0c;仅供学习分析的方法。 睡眠质量作为人类健康的重要指标&#xff0c;受到多种复杂因素的共同影响&#xff0c;包括生理状况、生活习惯、环境因素以及心理状态等多个方面。这些因素在不同的情境…

编译内核lspcu 工具源码 util-linux

1. 获取源码 wget https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.34/util-linux-2.34.tar.xz 2. 解压 tar xvf util-linux-2.34.tar.gz cd util-linux-2.34 本次实验环境&#xff1a;使用云主机 1.查看Lscpu , dmesg ,lsblk 等版本 我们看到这些指令都是…

JSP 指令标识和脚本标识的使用

文章目录 前言一、JSP 页面是什么&#xff1f;二、JSP 基本语法 1.指令标识 &#xff08;1&#xff09;page 指令&#xff08;2&#xff09;include 指令&#xff08;3&#xff09;taglib 指令2.脚本标识总结 前言 在进行Java Web 应用开发的过程中&#xff0c;JSP 是必不可少的…

全流程管理的商标管理软件如何实现一站式品牌保护?

如今&#xff0c;企业对于商标管理的需求已不再局限于单一的申请流程&#xff0c;而是扩展到了包括撤三、无效宣告、异议处理、维权行动乃至诉讼解决在内的全业务范畴。面对这一复杂多变的挑战&#xff0c;一款能够灵活应对、全面覆盖的可全业务管理商标管理软件成为了企业品牌…

湖北智彩星科技有限公司:AR共享游乐设备,让快乐加倍升级!

在科技日新月异的今天&#xff0c;娱乐方式正经历着前所未有的变革。湖北智彩星科技有限公司&#xff0c;作为行业内的佼佼者&#xff0c;凭借其创新的AR&#xff08;增强现实&#xff09;共享游乐设备&#xff0c;为大众带来了一场前所未有的娱乐盛宴&#xff0c;让快乐体验实…

在项目管理中,项目进度由哪些要素决定?

在项目管理领域&#xff0c;项目进度受到多种要素的综合影响。以下是一些关键的决定要素&#xff1a; 一、项目范围 1、任务清单 明确的任务清单是项目进度的基础。详细列出项目中需要完成的各项任务&#xff0c;包括任务的先后顺序、并行任务等&#xff0c;直接关系到进度规划…

中国土地利用覆盖和变化数据集(1980-2021)

该数据集通过融合森林资源清查数据和20种遥感土地利用产品&#xff0c;重建生成了1980-2015年中国森林覆盖数据集&#xff0c;空间分辨率为11公里。并且在此基础上进一步获得高精度森林覆被信息和土地利用覆盖数据集相融合&#xff0c;生成了中国1980-2021年土地利用覆盖和变化…

Vue3 + Vite Web项目 Electron 打包桌面应用程序

在根目录下创建 electron 文件夹 创建 electron/main.js 文件&#xff1a; // 导入模块 const { app, BrowserWindow ,Menu } require(electron) const path require(path)// 创建主窗口 const createWindow () > {const mainWindow new BrowserWindow({width: 1440…

RHEL7(RedHat红帽)软件安装教程

目录 1、下载RHEL7镜像 2、安装RedHat7 注&#xff1a;如果以下教程不想看&#xff0c;可以远程控制安装V:OYH-Cx330 【风险告知】 本人及本篇博文不为任何人及任何行为的任何风险承担责任&#xff0c;图解仅供参考&#xff0c;请悉知&#xff01;本次安装图解是在一个全新的演…

【网络安全】TCP和UDP

一、TCP/UDP对比 1.共同点&#xff1a; 都是工作在TCP/IP体系结构的传输层的协议 工作主要都是把端口号往原始数据封装 在 TCP 协议中&#xff0c;原始数据指的是应用程序产生的需要通过网络进行传输的数据。这些数据可以是各种类型的信息&#xff0c;例如文本、图像、音频、…