当前位置: 首页 > news >正文

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存在多组值。

相关文章:

C++笔记---set和map

1. 序列式容器与关联式容器 前面我们已经接触过STL中的部分容器如&#xff1a;string、vector、list、deque、array、forward_list等&#xff0c;这些容器统称为序列式容器&#xff0c;因为逻辑结构为线性序列的数据结构&#xff0c;两个位置存储的值之间一般没有紧密的关联关…...

HTTP 教程

HTTP/HTTPS 简介 HTTP&#xff08;Hypertext Transfer Protocol&#xff0c;超文本传输协议&#xff09;和 HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff0c;超文本传输安全协议&#xff09;是用于在网络中传输信息的两种主要协议。它们定义了客户端和服务器…...

低代码革命:加速云原生时代的端到端产品创新

随着云计算技术的飞速发展&#xff0c;云原生成为了企业数字化转型的重要方向。云原生技术通过容器化、微服务、持续集成/持续部署&#xff08;CI/CD&#xff09;等实践&#xff0c;帮助企业构建和运行可扩展的应用程序。然而&#xff0c;云原生技术的复杂性也给开发团队带来了…...

力扣 92.反转链表Ⅱ

力扣《反转链表》系列文章目录 刷题次序&#xff0c;由易到难&#xff0c;一次刷通&#xff01;&#xff01;&#xff01; 题目题解206. 反转链表反转链表的全部 题解192. 反转链表 II反转链表的指定段24. 两两交换链表中的节点两个一组反转链表 题解225. K 个一组翻转链表K …...

2024年最新版TypeScript学习笔记——泛型、接口、枚举、自定义类型等知识点

今天带来的是来自尚硅谷禹神2024年8月最新的TS课程的学习笔记&#xff0c;不得不说禹神讲的是真的超级棒&#xff01; 文章目录 TS入门JS中的困扰静态类型检查编译TS命令行编译自动化编译 类型检查变量和函数类型检查字面量类型检查 类型推断类型声明声明对象类型声明函数类型…...

java项目之城镇保障性住房管理系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的城镇保障性住房管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 城镇保障性住房管…...

无人机之航线规划篇

无人机的航线规划是一个复杂但至关重要的过程&#xff0c;它确保了无人机在飞行过程中的安全、高效以及任务的顺利完成。以下是对无人机航线规划的详细解析&#xff1a; 一、定义与目的 无人机航线规划是指依据无人机任务分配&#xff0c;规划出符合安全条件的飞行航线。这一过…...

828 华为云征文|华为 Flexus 云服务器搭建 PicGo 图床

在这个充满非凡意义的日子里&#xff0c;我怀揣着满心的热忱与憧憬&#xff0c;毅然决然地踏上了借助华为 Flexus 云服务器搭建 PicGo 图床的精彩征程。这段旅程&#xff0c;注定充满了无数的挑战与意外之喜&#xff0c;宛如在广袤无垠的数字海洋中勇敢地探寻那神秘而珍贵的宝藏…...

Zabbix 6.4添加中文语言

/usr/share/zabbix/include/locales .inc .phplocale -agrep “zh_CN" yum install langpacks-zh_CN.noarch y y y...

【退役之再次线上部署】Spring Boot + VUE + Nginx + MySQL

这篇博客写在凌晨 4 点 20 分&#xff0c;这个时候我刚线上部署完成 web 项目&#xff0c;自己写的全栈项目 这个点儿&#xff0c;也睡不着了&#xff0c;索性就写篇博客记录一下 一、踩坑实录 这个是 最重要的&#xff0c;所以写在前面 Nginx 配置文件 location location /a…...

Qanything 2 0源码解析系列1:新建知识库

Qanything 2.0源码解析系列1&#xff1a;新建知识库 文章转载自&#xff1a;https://www.feifeixu.top/article/19c76951-5881-4181-bb63-4188b28d3917 &#x1f600; 前言&#xff1a; qanything所有接口都定义在sanic_api.py中 接口函数定义在同级目录下的handler.py中 新建…...

Redis-01 入门和十大数据类型

Redis支持两种持久化方式&#xff1a;RDB持久化和AOF持久化。 1.RDB持久化是将Redis的数据以快照的形式保存在磁盘上&#xff0c;可以手动触发或通过配置文件设置定时触发。RDB保存的是Redis在某个时间点上的数据快照&#xff0c;可以通过恢复RDB文件来恢复数据。 2.AOF持久化…...

IT行业的现状与未来发展趋势

IT行业的现状与未来发展趋势 近年来&#xff0c;随着科技的迅猛发展&#xff0c;IT行业无疑已经成为全球经济增长的重要驱动力之一。无论是人工智能、大数据&#xff0c;还是云计算和区块链技术&#xff0c;IT行业的创新始终在不断推动着各个领域的变革。 人工智能的广泛应用…...

828华为云征文 | 云服务器Flexus X实例,Docker集成搭建Jenkins CI/CD平台

828华为云征文 | 云服务器Flexus X实例&#xff0c;Docker集成搭建Jenkins CI/CD平台 Jenkins 是一个开源的自动化服务器&#xff0c;用于持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;软件项目。它允许开发人员在软件开发过程中自动化各种任务&…...

今日 leetCode 15.三数之和

15. 三数之和 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元…...

Games101笔记-二维Transform变换(二)

1、什么是Transform Transform就是通过一个矩阵&#xff0c;进行缩放、旋转、平移等变换 2、缩放、旋转、切变、平移等基础变换 缩放变换&#xff1a; 反射变换&#xff1a; 切变&#xff1a; 绕原点旋转&#xff1a; 以上都是线性变换&#xff1a; 平移变换&#xf…...

【洛谷】AT_abc371_c [ABC371C] Make Isomorphic 的题解

【洛谷】AT_abc371_c [ABC371C] Make Isomorphic 的题解 洛谷传送门 AT传送门 题解 抽象题目&#xff0c;抽象翻译&#xff0c;可能是我太菜了&#xff0c;根本没看懂题目&#xff0c;后面是听大佬讲题才发现&#xff0c;这不就是一题全排列暴力题吗。谔谔&#xff0c;真的…...

全国职业院校技能大赛(大数据赛项)-平台搭建Spark、Scala笔记

Spark作为一个开源的分布式计算框架拥有高效的数据处理能力、丰富的生态系统、多语言支持以及广泛的行业应用。Scala是一种静态类型的编程语言&#xff0c;它结合了面向对象编程和函数式编程的特性&#xff0c;被誉为通用的“大数据语言”。而二者的结合更能迸发出新奇的化学反…...

【Java】JVM基本组成

一、JDK、JRE、JVM JDK&#xff1a;全称 “Java Development Kit” Java 开发工具包&#xff0c;提供 javac编译器、jheap、jconsole 等监控工具; JRE&#xff1a;全称 “Java Runtime Environment” Java 运行环境&#xff0c;提供 class Library 核心类库JVM; …...

解决【WVP服务+ZLMediaKit媒体服务】加入海康摄像头后,能发现设备,播放/点播失败,提示推流超时!

环境介绍 每人搭建的环境不一样&#xff0c;情况不一样&#xff0c;但是原因都是下面几种&#xff1a; wvp配置不当网络端口未放开网络不通 我搭建的环境&#xff1a; WVP服务&#xff1a;windows下&#xff0c;用idea运行的源码 ZLM服务&#xff1a;虚拟机里 问题描述 1.…...

盟接之桥®:当新ERP撞上“紧急接入”,WebEDI如何成为制造业的“救命稻草”?

在制造业的数字化征途中&#xff0c;最令人焦虑的场景之一莫过于&#xff1a;“下游客户&#xff08;如汽车主机厂&#xff09;明天就要看EDI对接数据&#xff0c;而你们的全新ERP系统&#xff0c;还在测试环境里试运行。”这绝非危言耸听。在汽车供应链、高端装备制造等领域&a…...

旧Mac焕新:使用OpenCore Legacy Patcher让2008-2017年设备支持最新macOS系统

旧Mac焕新&#xff1a;使用OpenCore Legacy Patcher让2008-2017年设备支持最新macOS系统 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 老旧设备升级正成为越…...

Phi-3-mini-4k-instruct-gguf代码实例:curl健康检查与supervisor服务管理实操

Phi-3-mini-4k-instruct-gguf代码实例&#xff1a;curl健康检查与supervisor服务管理实操 1. 模型简介与部署准备 Phi-3-mini-4k-instruct-gguf是微软Phi-3系列中的轻量级文本生成模型GGUF版本&#xff0c;特别适合问答、文本改写、摘要整理和简短创作等场景。这个经过优化的…...

【AI】可以操控鼠标的智能体

2026-04-02&#xff0c;以下是当前&#xff08;截至2026年初&#xff09;可以操作鼠标的AI智能体最新格局&#xff0c;分为操作系统级控制&#xff08;真鼠标键盘控制&#xff09;和浏览器级控制两类&#xff1a;第一梯队&#xff1a;操作系统级鼠标控制&#xff08;全桌面操控…...

如何快速集成gh_mirrors/ca/card到React/Vue/Angular:打造专业信用卡表单的完整指南

如何快速集成gh_mirrors/ca/card到React/Vue/Angular&#xff1a;打造专业信用卡表单的完整指南 【免费下载链接】card :credit_card: make your credit card form better in one line of code 项目地址: https://gitcode.com/gh_mirrors/ca/card gh_mirrors/ca/card是一…...

医疗AI推理可视化卡顿难题(实时渲染延迟>120ms?)——三甲医院PACS系统C++底层优化全链路拆解

第一章&#xff1a;医疗AI推理可视化卡顿难题的临床影响与性能基线定义在放射科、病理科及急诊超声等实时决策场景中&#xff0c;AI模型输出热力图、分割掩码或病灶定位框后&#xff0c;若前端渲染延迟超过300ms&#xff0c;将直接干扰医师对动态影像序列&#xff08;如心脏搏动…...

SEO的黑帽和白帽技术分别是什么_如何查询网站的SEO指标和排名数据

SEO的黑帽和白帽技术分别是什么_如何查询网站的SEO指标和排名数据 在当今的互联网时代&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;是提升网站流量和可见度的关键。SEO有许多技术和方法&#xff0c;其中包括白帽技术和黑帽技术。了解这些技术不仅有助于提升网站的搜索…...

寒武纪高级系统软件工程师面试技术解析

1. 寒武纪高级系统软件工程师面试全解析 作为一名在芯片验证领域摸爬滚打多年的工程师&#xff0c;去年我经历了寒武纪高级系统软件工程师岗位的完整面试流程。这个岗位对系统底层和芯片验证的要求非常高&#xff0c;今天我就把两轮技术面的核心问题拆解给大家&#xff0c;并分…...

2026知识付费SaaS避坑指南:数据安全与系统稳定性实测,创客匠人为何值得托付?

在知识付费行业&#xff0c;大多数选型对比只关注“前台功能”&#xff1a;能不能卖课、能不能直播、有没有拼团。但真正决定生意生死的&#xff0c;往往是看不见的“底层能力”——数据是否安全&#xff1f;系统是否稳定&#xff1f;学员资产能否真正归你所有&#xff1f;过去…...

9 鸿蒙页面渲染效率优化实战 | 鸿蒙开发筑基实战

9 鸿蒙页面渲染效率优化实战 | 鸿蒙开发筑基实战 作者&#xff1a;杨建宾&#xff08;华夏之光永存&#xff09; 摘要 本文聚焦鸿蒙应用页面渲染卡顿、掉帧、长列表加载缓慢等核心痛点&#xff0c;梳理页面渲染全流程的通用优化方案&#xff0c;从布局规范、组件复用、渲染管控…...