【C++笔记】map和set的使用

前言

各位读者朋友们大家好!上期我们讲完了二叉搜索树这一数据结构,这一期我们来讲STL中的map和set这两大容器。这两个容器的底层是红黑树,红黑树的底层是平衡二叉搜索树。

目录

  • 前言
  • 一. 序列式容器和关联式容器
  • 二. set系列的使用
    • 2.1 set类的介绍
    • 2.2 set的构造和迭代器
    • 2.3 set的增删查
      • 2.3.1 set的增删查
      • 2.3.2 [lower_bound](https://legacy.cplusplus.com/reference/set/set/lower_bound/)和[upper_bound](https://legacy.cplusplus.com/reference/set/set/upper_bound/)
      • 2.3.3 迭代器失效问题
    • 2.4 multiset和set的差异
    • 2.5 set的OJ题
  • 三. map系列的使用
    • 3.1 map类的介绍
    • 3.2 pair类型介绍
    • 3.3 map的构造
    • 3.4 map的增删查
    • 3.5 map数据的修改
    • 3.6 map和multimap的区别
    • 3.7 map的OJ题
  • 结语

一. 序列式容器和关联式容器

前面我们已经接触过STL中的部分容器如:string、vector、list、deque、array、forward_list等,这些容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间一般没有紧密的关联关系,比如交换一下,它依旧是序列式容器。顺序容器中的元素是按他们在容器中的存储位置来顺序保存和访问的。
关联式容器也是用来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是非线性结构,两个位置有紧密的关联关系,交换一下,它的存储结构就被破坏了。顺序容器中的元素是按关键字来保存和访问的。关联式容器有map/set系列和unordered_map/unordered_set系列。
map和set底层是红黑树,红黑树是平衡二叉搜索树。set是key搜索场景的结构,map是key/value搜索场景的结构。

二. set系列的使用

2.1 set类的介绍

set的文档
set的声明如下,T就是set的底层关键字的类型
在这里插入图片描述

  • set默认要求T支持小于比较,如果不支持或者想按自己的需求实现可以自己实现仿函数传给第二个模板参数。
  • set的底层存储数据是从空间配置器申请的,如果需要可以自己实现内存池,传给第三个参数。
  • 一般情况下我们不需要传第二个和第三个模板参数。
  • set的底层是用红黑树实现,增删查的时间复杂度是O(logN),迭代器遍历走的是二叉搜索树的中序,所以是有序的。

2.2 set的构造和迭代器

  • set的构造
  1. 无参构造
    在这里插入图片描述

  2. 迭代器区间构造
    在这里插入图片描述
    这里的迭代器区间是任意类型容器的迭代器

  3. 拷贝构造
    在这里插入图片描述

  4. initializer_list initializer 列表构造
    在这里插入图片描述

  • set的迭代器

在这里插入图片描述
set的迭代器是单向迭代器,因此只支持++操作
在这里插入图片描述

2.3 set的增删查

2.3.1 set的增删查

  • set插入数据
  1. pair<iterator,bool> insert (const value_type& val)

在这里插入图片描述
插入单个数据,可以看出set是不允许插入相同的数据的

  1. void insert (initializer_list<value_type> il)
    在这里插入图片描述

  2. template void insert (InputIterator first, InputIterator last);
    迭代器区间插入
    在这里插入图片描述
    这里的迭代器也是任意容器的迭代器

  • set查找数据
  1. 查找val,返回val所在的迭代器,没有找到返回end()
    在这里插入图片描述
    在这里插入图片描述

  2. count在这里插入图片描述
    因为set中不允许有重复的值,所以count的返回值是1,就说明set中存有val数据,反之没有
    在这里插入图片描述
    set的find和算法库中的find,set中的时间复杂度是O(logN),因为走的是二叉搜索树的搜索逻辑;算法库中的时间复杂度是O(N),是遍历查找

  • set删除数据

在这里插入图片描述
返回值是删除位置下一元素的迭代器

  1. 删除⼀个迭代器位置的值
    iterator erase (const_iterator position);
    在这里插入图片描述
  2. 删除val,val不存在返回0,存在返回1
    size_type erase (const value_type& val);
    在这里插入图片描述
  3. 删除⼀段迭代器区间的值
    iterator erase (const_iterator first, const_iterator last);
    在这里插入图片描述

2.3.2 lower_bound和upper_bound

在这里插入图片描述

在这里插入图片描述
这里的it1返回的是5位置的迭代器,it2返回的是6位置的迭代器,运用这两个成员函数,我们也可以删除一段数据区间,因为erase删除的区间是左闭右开的区间,所以左迭代器我们使用lower_bound函数来找,右迭代器使用upper_bound函数中找。

void test_set02()
{set<int> st({ 1,2,3,4,5,60,20,70,100,98});// 删除20~98的数据//auto it1 = st.lower_bound(20);//auto it2 = st.upper_bound(98);// 因为这个函数返回的是大于98的迭代器,所以可以将98删除// 删除15~65的数据auto it1 = st.lower_bound(15);auto it2 = st.upper_bound(65);st.erase(it1, it2);for (auto a : st){cout << a << " ";}cout << endl;
}

不用担心数据在set中不存在的问题,删哪段数据就相应的传哪些数据即可
在这里插入图片描述

2.3.3 迭代器失效问题

在这里插入图片描述
使用库里的erase之后更新迭代器是可以使用的
在这里插入图片描述

迭代器失效分为两种情况:
在这里插入图片描述
所以删除后的迭代器不要使用了,如果要使用,更新后再使用

2.4 multiset和set的差异

multiset和set的使用基本完全相似,主要区别在于multiset支持存储相同的值,那么insert/find/count/erase都围绕着支持存储相同的值而有所差异

  • insert
    在这里插入图片描述
    和set相比,multiset支持存储相等的值,也会排序,不会去重

  • find
    在这里插入图片描述
    find返回的是中序遍历的第一个x的迭代器,因为这样可以通过迭代器自增找到后续的值为x节点。
    在这里插入图片描述

  • count
    在这里插入图片描述
    count返回的是在set中值为x的实际节点个数

  • erase
    在这里插入图片描述
    会删除所有值为val的节点。

2.5 set的OJ题

  • 两个数组的交集 - 力扣(LeetCode)

在这里插入图片描述
在这里插入图片描述

class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {vector<int> ret;// 将数组中的数据放入set中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)// 相等放进新数组{ret.push_back(*it1);++it1;++it2;}else if(*it1<*it2)++it1;else++it2;}return ret;}
};
  • 环形链表II
    在这里插入图片描述
    在这里插入图片描述
class Solution {
public:ListNode *detectCycle(ListNode *head) {set<ListNode*> s;ListNode* cur = head;while(cur){if(s.count(cur) == 1)return cur;s.insert(cur);cur = cur->next;}return nullptr;}
};

三. map系列的使用

3.1 map类的介绍

map的参考文档
map的声明如下,Key就是map底层关键字的类型,T是map底层value的类型,set默认要求Key支持小于比较,如果不支持或者需要的话可以自己实现仿函数传给第二个模板参数,map的底层存储数据的内存是在空间配置器申请的。一般情况下,我们不需要传后两个模板参数。map的底层是用红黑树实现,增删查改的时间复杂度是O(logN),迭代器遍历走的是中序,所以是按Key有序顺序遍历的。
在这里插入图片描述

3.2 pair类型介绍

map底层的红黑树节点中的数据,使用pair<Key,T>存储键值对数据,也就是说map存的是pair,pair中又存了key和value
pair的文档
pair的底层:

typedef pair<const Key, T> value_type;
template <class T1, class T2>
struct pair
{typedef T1 first_type;typedef T2 second_type;T1 first;T2 second;pair() // 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){}
};
template <class T1, class T2>
inline pair<T1, T2> make_pair(T1 x, T2 y)
{return (pair<T1, T2>(x, y));
}

3.3 map的构造

map支持正向和反向迭代遍历,遍历默认按key的升序顺序,因为底层是二叉搜索树,迭代器遍历走的是中序,支持迭代器就意味着支持范围for,map支持修改value数据,不支持修改key数据,修改关键字数据就会破坏底层搜索树的结构。

  • 无参构造
    在这里插入图片描述
  • 迭代器区间构造
    在这里插入图片描述
  • 拷贝构造
    在这里插入图片描述

3.4 map的增删查

map的增加数据的接口,插入pair键值对数据,和set不同,但是查和删的接口只用关键字key和set是相同的,不过find返回iterator,不仅仅确认key在不在,还可以找到key映射的value,同时通过迭代器还可以修改value

  1. 增加数据
  • 单个数据插⼊,如果已经key存在则插入失败,key存在相等value不相等也会插入失败
    pair<iterator,bool> insert (const value_type& val);
    在这里插入图片描述

  • 列表插入,已经在容器中存在的值不会插入
    void insert (initializer_list<value_type> il);
    在这里插入图片描述

  • 迭代器区间插入
    在这里插入图片描述

  1. 查找
  • 查找key,返回key所在的迭代器,没有就返回end()
    在这里插入图片描述
  • 查找key,返回k的个数
    size_type count (const key_type& k) const;
    在这里插入图片描述
  1. 删除
    在这里插入图片描述
  • 删除⼀个迭代器位置的值
    iterator erase (const_iterator position);
    在这里插入图片描述
    删除第二个位置的值
  • 删除key,key存在返回0,存在返回1
    size_type erase (const key_type& k);
    在这里插入图片描述
  • 删除⼀段迭代器区间的值
    iterator erase (const_iterator first, const_iterator last);
    在这里插入图片描述

3.5 map数据的修改

前面提到map支持修改mapped_type数据,不支持修改key数据,修改关键字数据,破坏了底层搜索树的结构。map第一个支持修改的方式是通过迭代器,迭代器遍历时或者find返回key所在的iterator修改,map还有一个非常重要的修改接口operator[],但是operator[]不仅仅支持修改,还支持插入数据和查找数据,所以它是⼀个多功能复合接口需要注意从内部实现角度,map这里把我们传统说的value值,给的是T类型typedef为mapped_type。而value_type是红黑树结点中存储的pair键值对值。日常使用我们还是习惯将这里的T映射值叫做value。
在这里插入图片描述
operator[]
在这里插入图片描述

// operator的内部实现 
mapped_type& operator[] (const key_type& k)
{pair<iterator, bool> ret = insert({ k, mapped_type() });iterator it = ret.first;return it->second;
}

在这里插入图片描述
正常插入是插入+修改的功能
插入失败是查找+修改的功能
返回值是节点value的引用
在这里插入图片描述

3.6 map和multimap的区别

multimap和map的使用基本完全类似,主要区别点在于multimap支持关键值key冗余,那么insert/find/count/erase都围绕着支持关键值key冗余有所差异,这里跟set和multiset完全⼀样,比如find时,有多个key,返回中序第一个。其次就是multimap不支持[],因为支持key冗余,[]就只能支持插入了,不能支持修改。
equal_range
返回key相等值的迭代器区间
在这里插入图片描述
在这里插入图片描述
把所有字符对应的value打印出来。

3.7 map的OJ题

  • 随机链表的复制
    在这里插入图片描述
class Solution {
public:Node* copyRandomList(Node* head) {Node* copyhead = nullptr,*copytail = nullptr;Node* cur = head;map<Node*,Node*> mp;// 拷贝节点,建立映射关系while(cur){if(copyhead == nullptr){copyhead = copytail = new Node(cur->val);}else{copytail->next = new Node(cur->val);copytail = copytail->next;}mp[cur] = copytail;cur = cur->next;}// 链接random节点cur = head;Node* copyNode = copyhead;while(cur){if(cur->random == nullptr){copyNode->random = nullptr;}else{copyNode->random = mp[cur->random];// cur->random是一个节点,在map中找这个节点的映射// 赋给拷贝节点的random指针	}cur = cur->next;copyNode = copyNode->next;}return copyhead;}
};

结语

以上我们就讲完了map和set的使用,希望对大家有所帮助,感谢大家的阅读,欢迎大家批评指正!

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

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

相关文章

IO进程学习笔记

man手册 普通命令。系统调用的函数。库函数。特殊文件。文件格式。游戏。附加的一些变量 IO介绍 I&#xff1a;input 输入 O&#xff1a;output 输出 对文件的输入和输出 输入-》写文件&#xff0c;将文件中的内容写到内存中去 输出-》读文件&#xff0c;将内存中的内容读取到文…

基于STM32的手势电视机遥控器设计

目录 引言系统设计 硬件设计软件设计系统功能模块 手势识别模块遥控信号发送模块控制接口模块控制算法 手势识别算法遥控信号映射算法代码实现 手势识别与处理遥控信号发送系统调试与优化结论与展望 1. 引言 随着智能家居和物联网技术的发展&#xff0c;传统的电视遥控器逐渐…

哈希表实现

哈希概念 哈希&#xff08;hash&#xff09;又称散列&#xff0c;是一种组织数据的方式。从译名来看&#xff0c;有散乱排列的意思。本质就是通过哈希函数把关键字 Key 跟存储位置建立一个映射关系&#xff0c;查找时通过这个哈希函数计算出 Key 存储的位置&#xff0c;进行快…

CSS学习记录08

CSS文本颜色 文本颜色 color属性用于设置文本的颜色&#xff0c;颜色由以下值指定&#xff1a; 颜色名-比如“red"十六进制值-比如”#ff0000"RGB值-比如&#xff1a;“rgb&#xff08;255,0,0)”等。 页面的默认文本颜色在body选择器中定义的。 body {color: bl…

电子商务人工智能指南 6/6 - 人工智能生成的产品图像

介绍 81% 的零售业高管表示&#xff0c; AI 至少在其组织中发挥了中等至完全的作用。然而&#xff0c;78% 的受访零售业高管表示&#xff0c;很难跟上不断发展的 AI 格局。 近年来&#xff0c;电子商务团队加快了适应新客户偏好和创造卓越数字购物体验的需求。采用 AI 不再是一…

R155 VTA 认证对汽车入侵检测系统(IDS)合规要求

续接上集“浅谈汽车网络安全车辆型式认证&#xff08;VTA&#xff09;的现状和未来发展”&#xff0c;有许多读者小伙伴有联系笔者来确认相关的R155 VTA网络安全审核要求&#xff0c;基于此&#xff0c;笔者将针对 R155 VTA 每一条网络安全审核细则来具体展开。 今天就先从汽车…

利用Java爬虫按关键字搜索淘宝商品

在当今数字化时代&#xff0c;获取和分析电子商务平台上的商品数据对于市场研究者、数据分析师或个人买家而言是一项非常有用的能力。本文将详细介绍如何利用Java爬虫技术按关键字搜索淘宝商品&#xff0c;并提供相应的代码示例。 1. 爬虫技术简介 爬虫&#xff08;Web Crawle…

数据结构——B-树

目录 一.常见的搜索结构 二.B-树概念 三.B-树的插入分析及实现 1.插入分析 2.插入实现 1. B-树的节点设计 2.插入key的过程 3.B-树的插入实现 4.B-树的验证 5.B-树的性能分析 四.B树和B*树 1.B树 2.B*树 3.总结 五.B-树的应用 1.索引 2.MySQL索引简介 1.MyIS…

【vue2】封装自定义的日历组件(二)之基础添加返回到今天的功能

在上次封装的日历组件的基础上&#xff0c;我们完善下&#xff0c;在月份变化后&#xff0c;返回到当前月份的的当天日期的显示。 效果展示 代码逻辑 高亮的UI样式美化 .calendar-day {color: #d7d7d7;width: 100px;line-height: 80px;text-align: center;box-sizing: borde…

连续大涨,汉王科技跑步进入AI应用舒适区

OpenAI正在进行的“12天12场直播”让行业再次沸腾&#xff0c;二级市场也在寻找AI应用的机会。这刺激了12月首周同花顺sora概念涨超11&#xff05;&#xff0c;远超同期大盘指数涨幅。 截至目前&#xff0c;“满血版”推理模型o1和月收费高达200美元的ChatGPT Pro订阅服务&…

沃丰科技智能客服在跨境电商独立站中的核心角色

随着全球化进程的加速和互联网技术的不断发展&#xff0c;跨境电商行业蓬勃兴起&#xff0c;为消费者提供了更广阔、更便捷的购物选择。在这样一个竞争激烈的市场环境中&#xff0c;优质的客户服务成为了企业脱颖而出的关键。沃丰科技智能客服凭借其先进的技术和人性化的设计理…

智创 AI 新视界 -- AIGC 重塑广告行业的创新力量(16 - 7)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

入门级捡垃圾工作站记录

入门级捡垃圾工作站记录 想法 一直想着拥有有一台自己的多功能机子&#xff0c;一个笔记本很难事事包办&#xff0c;本来打算配一个台式机&#xff0c;后来研究了一下&#xff0c;索性捡垃圾拼装的工作站&#xff0c;性价比更高&#xff0c;稳定性也更强&#xff0c;而且还可…

SpringBoot【三】多环境切换,实例演示

一、前言 实际的项目开发中&#xff0c;一个项目通常会存在多个环境&#xff0c;例如&#xff0c;开发环境、测试环境和生产环境等。不同环境的配置也不尽相同&#xff0c;例如开发环境使用的是开发数据库&#xff0c;测试环境使用的是测试数据库&#xff0c;而生产环境使用的是…

Node.js创建Express项目安装express-generator报错

一、在我进行Node.js项目开发时&#xff0c;使用Express框架构建一个Express项目&#xff0c;时报错&#xff1a; npm warn deprecated mkdirp0.5.1: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has change…

在 .NET 9 中让您的 OpenAPI(Swagger)文档 UI 变得出色

从 .NET 9 开始&#xff0c;默认模板中不再包含 Swagger UI webapi。虽然文档仍然包含在内&#xff0c;但现在通过调用MapOpenApi&#xff0c;UI 不再存在。很高兴&#xff0c;重新获得文档 UI 相对容易。但 UI 本来就很无聊&#xff0c;所以让我们来点更花哨的东西吧&#xff…

使用Kimi开发自己的问答应用

概述 Kimi是大家常用的一个人工智能助手&#xff0c;本文使用Kimi开发文档&#xff0c;以node作为后端&#xff0c;开发与一个问答系统 实现效果 Kimi简介 Kimi是由Moonshot AI开发的人工智能助手&#xff0c;擅长中文和英文对话。目标是帮助用户解决问题、提供信息和执行任…

2024.12.09标准IO(作业)

1、使用这fscanf和fprintf两个函数实现文件的拷贝。 #include <myhead.h>int main(int argc, const char *argv[]) {//使用这fscanf和fprintf两个函数实现文件的拷贝FILE *fp1 fopen("./1.txt","r"); //打开被拷贝的文件1.txtif(NULL fp1){perror…

JK软考小程序上线啦

经过一段时间的题库整理和录入&#xff0c;JK软考小程序终于和大家见面了&#xff01; 扫描识别赶紧体验吧&#xff1a; JK软考是一款专门为准备软考的考生设计的移动学习工具。JK软考集成了丰富的软考题目资源&#xff0c;通过便捷的操作界面和多样化的功能&#xff0c;帮助考…

40分钟学 Go 语言高并发:负载均衡与服务治理

负载均衡与服务治理 一、知识要点总览 模块核心内容技术实现难度负载策略轮询、权重、最小连接数自定义负载均衡器中服务降级服务降级、熔断降级、限流降级Hystrix模式高熔断机制熔断器状态机、失败计数、自动恢复Circuit Breaker高限流设计令牌桶、滑动窗口、计数器Rate Lim…