stl 容器 – map

stl 容器 – map

1. map 和 multimap的使用文档

参考文档 参考文档点这里哟 🌈 😘

2. map 类的介绍

map的声明如下

template < class Key, 		// map::key_type
class T, 				  // map::mapped_type
class Compare = less<Key>, // map::key_compare
class Alloc = allocator<pair<const Key,T> > //map::allocator_type> class map;

key就是 map的底层关键字的类型, T,是 map 底层的value的类型,set默认支持 key的小于比较, 如果不支持就需要自行实现小于比较,实现仿函数来支持,需要穿第二个模板参数, map底层的存储数据的内训是与空间适配器申请的,想要自己实现内存是就需要自己传入第三个参数。在一般情况下,我们不需要去管着后面两个参数。map的底层是 红黑树, 增删查改的效率的 O(logN),迭代器的遍历还是 中序 ,所以在遍历时,是按照 key有序遍历的。

3. pair类型的介绍

map底层的红黑树节点中的数据,使用 pair<key, T>存储的键值对数据

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(): 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) );
}

4. map的构造

map的构造我们关注下面的几个接口就可以了。

  • map支持正向和反向迭代器遍历,遍历默认按照 key的升序遍历

  • 底层为 二叉搜索树,迭代器遍历按照 中序遍历

  • 支持迭代器,就意味着支持 范围 for

  • map支持修改 value数据,不支持修改 key数据 ,修改关键字会破坏搜索二叉树的底层结构。

// empty (1) ⽆参默认构造 
explicit map (const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());
// range (2) 迭代器区间构造 
template <class InputIterator>map (InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& = allocator_type());
// copy (3) 拷⻉构造 
map (const map& x);
// initializer list (5) initializer 列表构造 
map (initializer_list<value_type> il,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type());// 迭代器是⼀个双向迭代器 
iterator -> a bidirectional iterator to const value_type// 正向迭代器 iterator begin();
iterator end();
// 反向迭代器 
reverse_iterator rbegin();
reverse_iterator rend();

5.map的增删查

map的增删查我们就只需要关注下面的几个接口就可以了: 😚🌈

  • map的增接口,插入 pair键值对数据, 和set不同的。
  • 其他的接口和 set类似,但是 find接口返回的 iterator不仅可以确定 key是否存在同时还可以通过 key访问和修改 vaule
Member typeskey_type -> The first template parameter (Key)mapped_type -> The second template parameter (T)value_type -> pair<const key_type,mapped_type>// 单个数据插⼊,如果已经key存在则插⼊失败,key存在相等value不相等也会插⼊失败 pair<iterator,bool> insert (const value_type& val);
// 列表插⼊,已经在容器中存在的值不会插⼊ 
void insert (initializer_list<value_type> il);
// 迭代器区间插⼊,已经在容器中存在的值不会插⼊ 
template <class InputIterator>void insert (InputIterator first, InputIterator last);
// 查找k,返回k所在的迭代器,没有找到返回end() 
iterator find (const key_type& k);
// 查找k,返回k的个数 
size_type count (const key_type& k) const;
// 删除⼀个迭代器位置的值 
iterator erase (const_iterator position);
// 删除k,k存在返回0,存在返回1 
size_type erase (const key_type& k);
// 删除⼀段迭代器区间的值 
iterator erase (const_iterator first, const_iterator last);
/ 返回⼤于等k位置的迭代器 iterator lower_bound (const key_type& k);
// 返回⼤于k位置的迭代器 
const_iterator lower_bound (const key_type& k) const;

5. map的数据修改

  • 第一个支持修改的方式是使用迭代器, 迭代器遍历时或者是 find返回的 key所在的 iterator进行修改。
  • operator[] 是一个十分重要的接口,它不仅仅支持访问修改, 还支持插如和查找数据,是一个符合接口!
  • 注意: map这里我们传统说的是 value值,给的是 T类型的数据, typedefmapped_typevalue_type 是红黑树节点中存储的 pair键值。日常我们还是习惯将 T的映射值叫做 value;
Member typeskey_type -> The first template parameter (Key)mapped_type -> The second template parameter (T)value_type -> pair<const key_type,mapped_type>// 查找k,返回k所在的迭代器,没有找到返回end(),如果找到了通过iterator可以修改key对应的mapped_type值 iterator find (const key_type& k);
// ⽂档中对insert返回值的说明 
// The single element versions (1) return a pair, with its member pair::first set to an iterator pointing to either the newly inserted element or to the element with an equivalent key in the map. The pair::second element in the pairis set to true if a new element was inserted or false if an equivalent key already existed.// insert插⼊⼀个pair<key, T>对象 // 1、如果key已经在map中,插⼊失败,则返回⼀个pair<iterator,bool>对象,返回pair对象first是key所在结点的迭代器,second是false // 2、如果key不在在map中,插⼊成功,则返回⼀个pair<iterator,bool>对象,返回pair对象first是新插⼊key所在结点的迭代器,second是true // 也就是说⽆论插⼊成功还是失败,返回pair<iterator,bool>对象的first都会指向key所在的迭代器 // 那么也就意味着insert插⼊失败时充当了查找的功能,正是因为这⼀点,insert可以⽤来实现operator[]// 需要注意的是这⾥有两个pair,不要混淆了,⼀个是map底层红⿊树节点中存的pair<key, T>,另⼀个是insert返回值pair<iterator,bool> pair<iterator,bool> insert (const value_type& val);
mapped_type& operator[] (const key_type& k);
// 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;
}

7. 构造遍历和增删查的使用样例

#include<iostream>
#include<map>
using namespace std;
int main()
{// initializer_list构造及迭代遍历 map<string, string> dict = { {"left", "左边"}, {"right", "右边"},{"insert", "插⼊"},{ "string", "字符串" } };//map<string, string>::iterator it = dict.begin();auto it = dict.begin();while (it != dict.end()){//cout << (*it).first <<":"<<(*it).second << endl;// map的迭代基本都使⽤operator->,这⾥省略了⼀个-> // 第⼀个->是迭代器运算符重载,返回pair*,第⼆个箭头是结构指针解引⽤取 pair数据 //cout << it.operator->()->first << ":" << it.operator->()->second << endl;cout << it->first << ":" << it->second << endl;++it;}cout << endl;
// insert插⼊pair对象的4种⽅式,对⽐之下,最后⼀种最⽅便 pair<string, string> kv1("first", "第⼀个");dict.insert(kv1);dict.insert(pair<string, string>("second", "第⼆个"));dict.insert(make_pair("sort", "排序"));dict.insert({ "auto", "⾃动的" });// "left"已经存在,插⼊失败 dict.insert({ "left", "左边,剩余" });// 范围for遍历 for (const auto& e : dict){cout << e.first << ":" << e.second << endl;}cout << endl;string str;while (cin >> str){auto ret = dict.find(str);if (ret != dict.end()){cout << "->" << ret->second << endl;}else{cout << "⽆此单词,请重新输⼊" << endl;}}// erase等接⼝跟set完全类似,这⾥就不演⽰讲解了 return 0;
}

8. map的迭代器和 []功能的样例

  • 样例1
#include<iostream>
#include<map>
#include<string>
using namespace std;
int main()
{// 利⽤find和iterator修改功能,统计⽔果出现的次数 string arr[] = { "苹果", "西⽠", "苹果", "西⽠", "苹果", "苹果", "西⽠", "苹果", "⾹蕉", "苹果", "⾹蕉" };map<string, int> countMap;for (const auto& str : arr){// 先查找⽔果在不在map中 // 1、不在,说明⽔果第⼀次出现,则插⼊{⽔果, 1} // 2、在,则查找到的节点中⽔果对应的次数++ auto ret = countMap.find(str);if (ret == countMap.end()){countMap.insert({ str, 1 });}else{ret->second++;}}for (const auto& e : countMap){cout << e.first << ":" << e.second << endl;}cout << endl;return 0;
}
#include<iostream>
#include<map>
#include<string>
using namespace std;
int main()
{// 利⽤[]插⼊+修改功能,巧妙实现统计⽔果出现的次数 string arr[] = { "苹果", "西⽠", "苹果", "西⽠", "苹果", "苹果", "西⽠", "苹果", "⾹蕉", "苹果", "⾹蕉" };map<string, int> countMap;for (const auto& str : arr){// []先查找⽔果在不在map中 // 1、不在,说明⽔果第⼀次出现,则插⼊{⽔果, 0},同时返回次数的引⽤,++⼀下就变成1次了 // 2、在,则返回⽔果对应的次数++ countMap[str]++;}for (const auto& e : countMap){cout << e.first << ":" << e.second << endl;}cout << endl;return 0;
}
  • 样例2

    #include<iostream>
    #include<map>
    #include<string>
    using namespace std;
    int main()
    {map<string, string> dict;dict.insert(make_pair("sort", "排序"));// key不存在->插⼊ {"insert", string()} dict["insert"];// 插⼊+修改 dict["left"] = "左边";// 修改 dict["left"] = "左边、剩余";// key存在->查找 cout << dict["left"] << endl;return 0;
    }
    1

    9. multimap和map的差异

    • multimap 和 map的使用基本一致,只要是 multimapkey支持冗余。
    • find时, 有多个这样的 key返回序列中的第一个。
    • multimap不支持 [] 的修改 ,但支持插入

好了,今天就到这,感恩比心💗

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机视觉cv2入门之车牌号码识别

前边我们已经讲解了使用cv2进行图像预处理与边缘检测等方面的知识&#xff0c;这里我们以车牌号码识别这一案例来实操一下。 大致思路 车牌号码识别的大致流程可以分为这三步&#xff1a;图像预处理-寻找车牌轮廓-车牌OCR识别 接下来我们按照这三步来进行讲解。 图像预处理 …

Spring Boot 3 + SpringDoc:打造接口文档

1、背景公司 新项目使用SpringBoot3.0以上构建&#xff0c;其中需要对外输出接口文档。接口文档一方面给到前端调试&#xff0c;另一方面给到测试使用。 2、SpringDoc 是什么&#xff1f; SpringDoc 是一个基于 Spring Boot 项目的库&#xff0c;能够自动根据项目中的配置、…

多路由器通过三层交换机互相通讯(单臂路由+静态路由+默认路由版),通过三层交换机让pc端相互通讯

多路由器通过三层交换机互相通讯&#xff08;单臂路由静态路由默认路由版&#xff09; 先实现各个小框框里能够互通 哇咔 交换机1&#xff08;二层交换机,可看配置单臂路由的文章) Switch>en Switch#conf t Switch(config)#int f0/1 Switch(config-if)#switchport access…

通过gird布局实现div的响应式分布排列

目标&#xff1a;实现对于固定宽度的div盒子在页面中自适应排布&#xff0c;并且最后一行的div盒子可以与前面的盒子对齐。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" con…

AI Agent系列(九) -Data Agent(数据分析智能体)

AI Agent系列【九】 前言一、Data Agent场景二、Data Agent核心因素2.1 数据源2.2 大模型2.3 应用及可视化 三、Data Agent应用场景 前言 Data Agent就是在大模型基础上构建一个数据分析的智能体&#xff0c;是一种基于人工智能技术&#xff0c;特别是大模型技术的数据分析智…

AUTOSAR图解==>AUTOSAR_SWS_DefaultErrorTracer

AUTOSAR 默认错误追踪器(Default Error Tracer)详细分析 基于AUTOSAR 4.4.0规范的深入解析 目录 概述 DET模块的作用DET模块的定位 架构设计 模块架构接口设计 状态与行为 状态转换错误报告流程 API与数据结构 API概览数据类型定义 配置与扩展 模块配置回调机制 总结 1. 概述 …

Linux,redis群集模式,主从复制,读写分离

redis的群集模式 主从模式 &#xff08;单项复制&#xff0c;主复制到从&#xff09; 一主两从 一台主机上的一主两从 需要修改三个配置文件 主要端口不一样 redis-8001.conf redis-8002.conf redis-8003.conf 哨兵模式 分布式集群模式 redis 安装部署 1&#xff0c;下载…

前端面试题---GET跟POST的区别(Ajax)

GET 和 POST 是两种 HTTP 请求方式&#xff0c;它们在传输数据的方式和所需空间上有一些重要区别&#xff1a; ✅ 一句话概括&#xff1a; GET 数据放在 URL 中&#xff0c;受限较多&#xff1b;POST 数据放在请求体中&#xff0c;空间更大更安全。 &#x1f4e6; 1. 所需空间…

WPF 从Main()方法启动

1.去掉App.xaml StartupUri“MainWindow.xaml” 只会让App.g.cs 不生成这行代码&#xff0c;但是还是会生成的App.g.cs文件中生成Main方法 this.StartupUri new System.Uri("MainWindow.xaml", System.UriKind.Relative);默认的App.xaml的生成操作是 应用程序定义…

ocr-身份证正反面识别

在阿里云官网&#xff0c;申请一个token [阿里官方]身份证OCR文字识别_API专区_云市场-阿里云 (aliyun.com) 观察一下post请求body部分json字符串&#xff0c;我们根据这个创建一个java对象 先默认是人像面 public class IdentityBody {public String image;class configure…

通过GO后端项目实践理解DDD架构

最近在工作过程中重构的项目要求使用DDD架构&#xff0c;在网上查询资料发现教程五花八门&#xff0c;并且大部分内容都是长篇的概念讲解&#xff0c;晦涩难懂&#xff0c;笔者看了一些github上入门的使用DDD的GO项目&#xff0c;并结合自己开发中的经验&#xff0c;谈谈自己对…

LangGraph中预构件,creat_react_agent的实现流程

LangGraph Prebuilt Agent 流程图 本文档展示了LangGraph的prebuilt模块中Agent的实现流程&#xff0c;重点是create_react_agent函数构建的代理系统流程和结构。 ReAct Agent构建流程 #mermaid-svg-ubcEEuBeApApT624 {font-family:"trebuchet ms",verdana,arial,s…