【C++】map详解

📢博客主页:https://blog.csdn.net/2301_779549673
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨

在这里插入图片描述

在这里插入图片描述

文章目录

  • 📢前言
  • 🏳️‍🌈一、pair类型介绍
  • 🏳️‍🌈二、map的增删查
  • 🏳️‍🌈三、map的数据修改
  • 🏳️‍🌈四、使用样例
  • 🏳️‍🌈五、multimap和map的差异
  • 👥总结


📢前言

map的结构和set很类似,部分功能就不演示了,上一篇博客中有

在这里插入图片描述
Map 是 C++ 中非常重要的关联容器之一。它以键值对的形式存储数据,其中每个键都是唯一的,这意味着不能有重复的键。如果尝试插入一个已存在的键,将会覆盖该键对应的值。

Map 的内部结构是红黑树,这使得它具有很多优点。首先,数据是有序的,这有助于高效地进行查找、插入和删除操作。查找、插入、删除的平均和最坏时间复杂度都是 O (log n),其中 n 是 map 中元素的个数。

例如,当我们需要存储学生的学号和姓名时,可以使用 map<int, string>,其中学号作为键,姓名作为值。这样可以通过学号快速地找到对应的学生姓名。

Map 的键和值可以是任意类型,但需要注意的是,如果键是自定义类型,需要为该类型提供小于运算符的重载,以便 map 能够对键进行排序。

在实际应用中,Map 非常适合用于需要快速查找和存储键值对的场景。比如,在字典应用中,可以将单词作为键,释义作为值,方便用户快速查询单词的含义。

总之,Map 以其高效的查找、插入和删除操作,以及有序性和唯一键的特点,在 C++ 编程中有着广泛的应用。


🏳️‍🌈一、pair类型介绍

在 C++ 中,pair类是一种模板类型,定义在<utility>头文件中。它将两个不同类型的值组合成一个单一的对象。对于map容器来说,map中的每个元素都是一个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) );
}

🏳️‍🌈二、map的增删查

map的增删查关注以下几个接口即可:

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

Member types
key_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

🏳️‍🌈三、map的数据修改

前面我提到map支持修改mapped type 数据,不支持修改key数据,修改关键字数据,破坏了底层搜索树的结构。

map第一个支持修改的方式时通过迭代器,迭代器遍历时或者find返回key所在的iterator修改,map还有一个非常重要的修改接口operator[ ],但是**operator[ ]**不仅仅支持修改,还支持插入数据和查找数据,所以他是一个多功能复合接口

需要注意从内部实现角度,map这里把我们传统说的value值,给的是T类型,typedef为mapped_type。而value_type是红黑树结点中存储的pair键值对值。日常使用我们还是习惯将这里的T映射值叫做value。

Member types
key_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 pair
//is 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;
}

🏳️‍🌈四、使用样例

构造遍历及增删查使用样例

#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;
}

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

#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;
}


#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;
}

🏳️‍🌈五、multimap和map的差异

multimap和map的使用基本完全类似,主要区别点在于multimap支持关键值key冗余,那么insert/find/count/erase都围绕着支持关键值key冗余有所差异,这里跟set和multiset完全一样,比如find时,有多个key,返回中序第一个。其次就是multimap不支持门,因为支持key冗余,"就只能支持插入了,不能支持修改。


👥总结


本篇博文对 map 做了一个较为详细的介绍,不知道对你有没有帮助呢

觉得博主写得还不错的三连支持下吧!会继续努力的~

请添加图片描述

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

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

相关文章

APP自动化搭建与应用

APP自动化环境搭建 用于做APP端UI自动化&#xff0c;adb连接手机设备。 需要的工具java编辑器&#xff1a;jdk、Android-sdk软件开发工具组、appium的python客户端、nodes.js、夜神模拟器、apk包、uiautomatorviewer 第一步&#xff1a;安装sdk&#xff0c;里面包含建立工具bu…

Spring Boot中线程池使用

说明&#xff1a;在一些场景&#xff0c;如导入数据&#xff0c;批量插入数据库&#xff0c;使用常规方法&#xff0c;需要等待较长时间&#xff0c;而使用线程池可以提高效率。本文介绍如何在Spring Boot中使用线程池来批量插入数据。 搭建环境 首先&#xff0c;创建一个Spr…

docker compose入门5—创建一个3副本的应用

1. 定义服务 version: 3.8 services:web:image: gindemo:v2deploy:replicas: 3ports:- "9090" 2. 启动服务 docker compose -f docker-compose.yml up -d 3. 查看服务 docker compose ps 4. 访问服务

LeetCode讲解篇之852. 山脉数组的峰顶索引

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们可以采用二分查找&#xff0c;每次查询区间中点元素与中点下一个元素比较 如果中点元素大于其下一个元素&#xff0c;则表示从中点开始向右是递减趋势&#xff0c;那峰值索引一定小于等于中点&#xff0c;我…

留存率的定义与SQL实现

1.什么是留存率 留存率是指在特定时间段内&#xff0c;仍然继续使用某项产品或服务的用户占用户总数的百分比。 通常&#xff0c;留存率会以日&#xff0c;周&#xff0c;或月为单位进行统计和分析。 2.SQL留存率常见问题 1.计算新用户登录的日期的次日留存率以及3日留存率 …

如何实现 C/C++ 与 Python 的通信?

在现代编程中&#xff0c;C/C与Python的通信已经成为一种趋势&#xff0c;尤其是在需要高性能和灵活性的场景中。本文将深入探讨如何实现这两者之间的互通&#xff0c;包括基础和高级方法&#xff0c;帮助大家在混合编程中游刃有余。 C/C 调用 Python&#xff08;基础篇&#…

生成正激波表的代码

k1.4 import math import numpy as np import pandas as pd #Ma1到p之比 def Ma2p(Ma1,k):return 2*k*Ma1**2/(k1)-(k-1)/(k1) def Ma2rho(Ma1,k):return (k1)*Ma1**2/(2(k-1)*Ma1**2) def Ma2T(Ma1,k):return 1/Ma1**2*(2/(k1))**2*(k*Ma1**2-(k-1)/2)*(1(k-1)/2*Ma1**2) def…

国外电商系统开发-运维系统文件上传

文件上传&#xff0c;是指您把您当前的PC电脑上的文件批量的上传到远程服务器上&#xff0c;在这里&#xff0c;您可以很轻松的通过拖动方式上传&#xff0c;只需要动动鼠标就搞定。 第一步&#xff0c;您应该选择要上传的服务器&#xff1a; 选择好了以后&#xff0c;点击【确…

小程序-全局数据共享

目录 1.什么是全局数据共享 2. 小程序中的全局数据共享方案 MboX 1. 安装 MobX 相关的包 2. 创建 MobX 的 Store 实例 3. 将 Store 中的成员绑定到页面中 4. 在页面上使用 Store 中的成员 5. 将 Store 中的成员绑定到组件中 6. 在组件中使用 Store 中的成员 1.什么是全…

谷歌发布了日语版的 Gemma2 模型——gemma-2-2b-jpn-it

Gemma 是一系列同类最佳的开放式模型&#xff0c;其灵感和技术源自 Gemini 系列模型。 它们是具有开放权重的文本到文本、纯解码器大型语言模型。 Gemma 模型非常适合各种文本生成任务&#xff0c;包括问题解答、摘要和推理。 Gemma-2-JPN 是一个针对日语文本进行微调的 Gemma…

使用微服务Spring Cloud集成Kafka实现异步通信

在微服务架构中&#xff0c;使用Spring Cloud集成Apache Kafka来实现异步通信是一种常见且高效的做法。Kafka作为一个分布式流处理平台&#xff0c;能够处理高吞吐量的数据&#xff0c;非常适合用于微服务之间的消息传递。 微服务之间的通信方式包括同步通信和异步通信。 1&a…

【CTF Web】Pikachu CSRF(get) Writeup(CSRF+GET请求+社会工程学)

CSRF(跨站请求伪造)概述 Cross-site request forgery 简称为“CSRF”&#xff0c;在CSRF的攻击场景中攻击者会伪造一个请求&#xff08;这个请求一般是一个链接&#xff09;&#xff0c;然后欺骗目标用户进行点击&#xff0c;用户一旦点击了这个请求&#xff0c;整个攻击就完成…

vmstat命令:系统性能监控

一、命令简介 ​vmstat​ 是一种在类 Unix 系统上常用的性能监控工具&#xff0c;它可以报告虚拟内存统计信息&#xff0c;包括进程、内存、分页、块 IO、陷阱&#xff08;中断&#xff09;和 CPU 活动等。 ‍ 二、命令参数 2.1 命令格式 vmstat [选项] [ 延迟 [次数] ]2…

docker快速上手

一个轻量的虚拟机&#xff0c;让程序员不再纠结于环境部署&#xff0c;更多集中于代码编写&#xff0c;基础建设&#xff0c;开发 作用&#xff1a; 打包&#xff1a;把你软件运行所需的所有东西打包到一起 分发&#xff1a;把你打包好的“安装包”上传到一个镜像仓库&#…

渲染技术的教育普及,塑造未来视觉艺术与技术的璀璨星辰

在数字时代的浪潮中&#xff0c;渲染技术作为连接创意与现实的桥梁&#xff0c;正以前所未有的速度推动着视觉艺术与技术领域的融合与发展。从电影特效的震撼呈现到游戏世界的细腻构建&#xff0c;从广告设计的视觉冲击力到建筑设计方案的直观展示&#xff0c;渲染技术无处不在…

css 简单网页布局——浮动(一)

1. 三种布局方式 1.1 标准流 1.2 浮动的使用 1.3 简述浮动 1.3.1 浮动三大特性 <style>.out {border: 1px red solid;width: 1000px;height: 500px;}.one {background-color: aquamarine;width: 200px;height: 100px;}.two {background-color: blueviolet;width: 200px;h…

『网络游戏』窗口基类【06】

创建脚本&#xff1a;WindowRoot.cs 编写脚本&#xff1a; 修改脚本&#xff1a;LoginWnd.cs 修改脚本&#xff1a;LoadingWnd.cs 修改脚本&#xff1a;ResSvc.cs 修改脚本&#xff1a;LoginSys.cs 运行项目 - 功能不变 本章结束

【AI知识点】批归一化(Batch Normalization)

批归一化&#xff08;Batch Normalization&#xff0c;BN&#xff09; 是一种用于加速神经网络训练并提高模型稳定性的方法&#xff0c;通过在每一层对神经网络中的激活值进行标准化&#xff0c;使得每一层的输入保持在一个稳定的分布中&#xff0c;从而缓解梯度消失和梯度爆炸…

Chromium 搜索引擎功能浅析c++

地址栏输入&#xff1a;chrome://settings/searchEngines 可以看到 有百度等数据源&#xff0c;那么如何调整其顺序呢&#xff0c;此数据又存储在哪里呢&#xff1f; 1、浏览器初始化搜索引擎数据来源在 components\search_engines\prepopulated_engines.json // Copyright …

机器学习-支撑向量机SVM

Support Vector Machine 离分类样本尽可能远 Soft Margin SVM scikit-learn中的SVM 和kNN一样&#xff0c;要做数据标准化处理&#xff01; 涉及距离&#xff01; 加载数据集 import numpy as np import matplotlib.pyplot as plt from sklearn import datasetsiris datas…