•何为 map?

  map 是 STL 的一个关联容器,它提供一对一的数据处理,map 中存放的是一个 key-value键值对,其类型可以自己定义:

  • 第一个可以称为关键字,每个关键字在 map 中只能出现一次
  • 第二个称为该关键字的值

  由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。

  map 内部是一颗红黑树(一 种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在 map 内部所有的数据都是有序的。

•map的使用

头文件

  要想使用 map,必须要引入  #include<map> 。

定义

   map<类型1, 类型2>mymap; ,这样就定义了一个用 类型1 作为索引,并拥有相关联的指向 类型2 的指针。

  其中,类型1和类型2可以是常见的  int , double , bool , string 等类型,也可以放置  map<类型3, 类型4> ,这就属于嵌套 map 了。

  我们以 string-int 为例: map<string, int>mymap; ,并使其存储<姓名-年龄>对;

插入数据

  假设我们需要向 map 中插入如下数据:

    张三 18

    李四 20

    王五 24

  可以通过  insert() 函数实现插入操作。

通过 map::insert 插入数据

void add()
{
mymap.insert(pair<string, int>("张三", 18));
mymap.insert(pair<string, int>("李四", 20));
mymap.insert(pair<string, int>("王五", 24));
}

  通过  insert  向 map 中插入键值对  pair<string, int>(姓名, 年龄) ,其中 键值对 的类型一定要和 map 定义是的类型一一对应。

  每插入一个 键值对 都要重写一遍  pair<string, int> ,显得有些啰嗦,我们可以这样写:

#define psi pair<string, int>

void add()//添加数据
{
mymap.insert(psi("张三", 18));
mymap.insert(psi("李四", 20));
mymap.insert(psi("王五", 24));
}

  定义 psi 表示 <string, int> 的键值对,这样定义的话,在书写代码的时候就很简洁。

通过数组的方式插入数据

void add()//添加数据
{
mymap["张三"] = 18;
mymap["李四"] = 20;
mymap["王五"] = 24;
}

总结

  这两种方法,虽然都可以实现数据的插入,但是它们是有区别的:

  • 用 insert 插入数据,在数据的插入上涉及到集合的唯一性这个概念,即当 map 中有这个关键字时,insert 操作是插入不了数据的
  • 但是用数组方式就不同了,它可以覆盖以前该关键字对应的值

  例如,先插入一条数据 <张三 , 18>,然后分别通过 insert 和数组操作来修改张三的年龄为 180,并查看输出结果。

void add(map<string, int>mymap)//添加数据
{
mymap.insert(psi("张三", 18));
cout << mymap["张三"] << endl; mymap.insert(psi("张三", 180));//已存在"张三"数据,该插入操作不执行:张三-18
cout << mymap["张三"] << endl; mymap["张三"] = 180;//覆盖:张三-180
cout << mymap["张三"] << endl;
}

  输出结果为:

  通过输出结果,你会发现第二条 insert 并没有执行成功,但是通过数组的方式修改成功。

  学会了向 map 中添加数据后,怎样才能确定数据添加成功了呢?

  在学习遍历数据之前,先来了解一下迭代器的概念。

迭代器

  要访问顺序容器和关联容器中的元素,需要通过 迭代器(iterator) 进行。

  迭代器是一个变量,相当于容器和操纵容器的算法之间的中介,迭代器可以指向容器中的某个元素,通过迭代器就可以读写它指向的元素,从这一点上看,迭代器和指针类似。

  迭代器按照定义方式分成以下四种:

  • 正向迭代器: 容器类名::iterator 迭代器名;
  • 常量正向迭代器: 容器类名::const_iterator 迭代器名;
  • 反向迭代器:容器类名::reverse_iterator 迭代器名;
  • 常量反向迭代器:容器类名::const_reverse_iterator 迭代器名;

  通过迭代器可以读取它指向的元素, *迭代器 就表示迭代器指向的元素,通过非常量迭代器还能修改其指向的元素。

  迭代器都可以进行  ++ 操作,反向迭代器和正向迭代器的区别在于:

  • 对正向迭代器进行  ++ 操作作时,迭代器会指向容器中的后一个元素
  • 而对反向迭代器进行  ++ 操作时,迭代器会指向容器中的前一个元素

map遍历

  有了迭代器的相关知识,我买来看看如何通过 迭代器 遍历 map 中的数据。

正向迭代器

void print()//遍历
{
puts("正向迭代器");
map<string, int >::iterator it;//正向迭代器
for (it = mymap.begin(); it != mymap.end(); it++)
{
//it->second += 1;//可修改键对应的值
cout << it->first << " " << it->second << endl;
}
}

  首先通过  map<string, int >::iterator it 定义了迭代器 it,并在 for 循环中将 it 赋值为  map.begin() 表示从 map 的第一个元素开始访问,直到访问到  map.end() 为止;

  • it->first  表示读取 it 指向的 键值对 的键
  • it->second 表示读取 it 指向的 键值对 的值

  输出结果如下:

  对输出结果,有没有什么发现?

  提示一下,字典序 李(L) < 王(W) < 张(Z),而输入的顺序是 张三、李四、王五,通过输出可以看出 map 默认按照键升序排列。

  上述输出结果是正向输出的,那么,如果想要反向输出呢?

  这就需要使用反向迭代器了。

反向迭代器

void print()//遍历
{
puts("反向迭代器");
map<string, int >::reverse_iterator rit;//反向迭代器
for (rit = mymap.rbegin(); rit != mymap.rend(); rit++)
{
//rit->second += 2;//可修改值
cout << rit->first << " " << rit->second << endl; }
}

  输出结果:

  刚好和正向的相反,需要注意的是:

  • 正向迭代器搭配  begin() , end()
  • 反向迭代器搭配  rbegin() , rend()

常量正向、反向迭代器

void print()//遍历
{
puts("常量正向迭代器");
map<string, int >::const_iterator cit;//常量正向迭代器
for (cit = mymap.cbegin(); cit != mymap.cend(); cit++)
{
//cit->second += 3;//不可修改
cout << cit->first << " " << cit->second << endl;
} printf("-·-·-·-·-·-·-·-·-·-·-·-\n"); puts("常量反向迭代器");
map<string, int>::const_reverse_iterator crit;//常量反向迭代器
for (crit = mymap.crbegin(); crit != mymap.crend(); crit++)
{
//crit->second += 4;//不可修改
cout << crit->first << " " << crit->second << endl;
}
}
  • 常量正向迭代器搭配  cbegin() , cend()
  • 常量反向迭代器搭配  crbegin() , crend()

  搭配错了编译器会报错的。

判定某个关键字是否在map中出现

  可通过  find  或  count 实现。

1.通过 count 判断

void search()
{
if (mymap.count("张三") > 0)
cout << "张三查找成功" << endl;
else
cout << "张三查找失败" << endl; if (mymap.count("张四") > 0)
cout << "张四查找成功" << endl;
else
cout << "张四查找失败" << endl;
}

   count  返回类型为整数,由于 map 中的键是不重复的,所以  mymap.count(关键字) 只有两个取值 0 或 1;

2.通过 find 判断

void search()
{
map<string, int>::iterator it;
it = mymap.find("张三");
if (it != mymap.end())
cout << "张三查找成功,年龄为:" << it->second << endl;
else
cout << "张三查找失败" << endl; it = mymap.find("张四");
if (it != mymap.end())
cout << "张四查找成功,年龄为:" << it->second << endl;
else
cout << "张四查找失败" << endl; }

   find  返回类型为 迭代器,如果找到,返回 关键字 的迭代器,否则返回  map.end() 。

  通过 find 还可以定位该关键字,输出该关键字的值,所以在功能方面,  find 比  count 要强大;

CODE

#pragma warning(disable:4996)//在VS中取消返回值被忽略的报错
#pragma warning(disable:4786)//在VS中取消使用STL一些容器的报错
#include<iostream>
#include<map>
using namespace std;
#define psi pair<string, int> map<string, int>mymap; void add()//添加数据
{
//mymap.insert(psi("张三", 18));
//mymap.insert(psi("李四", 20));
//mymap.insert(psi("王五", 24)); mymap["张三"] = 18;
mymap["李四"] = 20;
mymap["王五"] = 24;
}
void search()
{
map<string, int>::iterator it;
it = mymap.find("张三");
if (it != mymap.end())
cout << "张三查找成功,年龄为:" << it->second << endl;
else
cout << "张三查找失败" << endl; it = mymap.find("张四");
if (it != mymap.end())
cout << "张四查找成功,年龄为:" << it->second << endl;
else
cout << "张四查找失败" << endl; }
void print()//遍历
{
puts("正向迭代器");
map<string, int >::iterator it;//正向迭代器
for (it = mymap.begin(); it != mymap.end(); it++)
{
//it->second += 1;//可修改值
cout << it->first << " " << it->second << endl;
} printf("-·-·-·-·-·-·-·-·-·-·-·-\n"); puts("反向迭代器");
map<string, int >::reverse_iterator rit;//反向迭代器
for (rit = mymap.rbegin(); rit != mymap.rend(); rit++)
{
//rit->second += 2;//可修改值
cout << rit->first << " " << rit->second << endl; } printf("-·-·-·-·-·-·-·-·-·-·-·-\n"); puts("常量正向迭代器");
map<string, int >::const_iterator cit;//常量正向迭代器
for (cit = mymap.cbegin(); cit != mymap.cend(); cit++)
{
//cit->second += 3;//不可修改
cout << cit->first << " " << cit->second << endl;
} printf("-·-·-·-·-·-·-·-·-·-·-·-\n"); puts("常量反向迭代器");
map<string, int>::const_reverse_iterator crit;//常量反向迭代器
for (crit = mymap.crbegin(); crit != mymap.crend(); crit++)
{
//crit->second += 4;//不可修改
cout << crit->first << " " << crit->second << endl;
} }
int main()
{
//freopen("E:\\Documents\\stdin&&stdout\\stdin\\文件名","r",stdin);//读文件
//freopen("E:\\Documents\\stdin&&stdout\\stdout\\文件名","w",stdout);//写文件 add(); printf("-·-·-·-·-·-·-·-·-·-·-·-\n");
print(); printf("-·-·-·-·-·-·-·-·-·-·-·-\n");
search(); return 0;
}

•题目推荐

  1.【华为机试题库——HJ8 合并表记录

•参考资料

  1.【std::map

  2.【C++迭代器(STL迭代器)iterator详解

  3.【C++中的STL中map用法详解

C++ STL之 map 学习笔记的更多相关文章

  1. C++STL标准库学习笔记(三)multiset

    C++STL标准库学习笔记(三)multiset STL中的平衡二叉树数据结构 前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标 ...

  2. C++STL标准库学习笔记(一)sort

    前言: 近来在学习STL标准库,做一份笔记并整理好,方便自己梳理知识.以后查找,也方便他人学习,两全其美,快哉快哉! 这里我会以中国大学慕课上北京大学郭炜老师的<程序设计与算法(一)C语言程序设 ...

  3. C++STL标准库学习笔记(五)set

    前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标记了出来,这一篇后面主要都是我的记录了,为了防止大片蓝色字体出现,后面就不改蓝色 ...

  4. C++STL标准库学习笔记(二)二分查找

    二.STL中的二分查找算法 1.binary_search 2.lower_bound 3.upper_bound 记得#include<algorithm>! 前言: 在这个笔记中,我把 ...

  5. map学习笔记

    collection是单列集合,map是双列集合.其中包含<k,v>键值对,注意:键具有唯一性,而值不唯一. 在此列举三个读取方式:keyset,valueset,及entryset. k ...

  6. STL之map学习实例

    ``` #include<iostream> #include<algorithm> #include<vector> #include<map> #i ...

  7. Python map学习笔记

    map是一个高阶用法,字面意义是映射,它的作用就是把一个数据结构映射成另外一种数据结构. map用法比较绕,最好是对基础数据结构很熟悉了再使用,比如列表,字典,序列化这些. map的基本语法如下: m ...

  8. C++STL标准库学习笔记(四)multiset续

    自定义排序规则的multiset用法 前言: 在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标记了出来,只不过这一次的笔记主要是我的补充 ...

  9. Scala学习笔记之:tuple、array、Map

    [TOC] 本文<快学Scala>的笔记 tuple学习笔记 tuple的定义 对偶是元组(tuple)的最简单形态--元组是不同类型的值的聚集. 元组的值是通过将单个值包含在圆括号中构成 ...

  10. stl源码剖析 详细学习笔记 set map

    // //  set map.cpp //  笔记 // //  Created by fam on 15/3/23. // // //---------------------------15/03 ...

随机推荐

  1. 使用Navicat 进行MySql数据库同步功能

    使用Navicat 进行MySql数据库同步功能 作者:胡德安 准备: 打开Navicat管理工具(比如Navicat Premium 15管理工具) 两个数据库第一个是源数据库A和要被同步的目标数据 ...

  2. arch linux 安装

    好长时间都没有更新自己的博客了,我简单翻阅了一下自己的更新记录,上一次更新好像还是在5月份左右,距今也有快半年,这半年也是遇到了很多事情,有不好的,也有好的.这半年我对在日常生活工作中使用Linux系 ...

  3. 21.12 Python 实现网站服务器

    Web服务器本质上是一个提供Web服务的应用程序,运行在服务器上,用于处理HTTP请求和响应.它接收来自客户端(通常是浏览器)的HTTP请求,根据请求的URL.参数等信息生成HTTP响应,并将响应返回 ...

  4. 字节码编程,Javassist篇四《通过字节码插桩监控方法采集运行时入参出参和异常信息》

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 字节码编程插桩这种技术常与 Javaagent 技术结合用在系统的非入侵监控中,这样 ...

  5. 使用私有gitlab搭建gitbook持续集成

    目录 环境搭建 1. 安装 Node.js 2. 安装 gitbook 3. 安装 Gitlab Runner 4. 注册Runner gitbook 配置 1. 目录结构 2. 命令行 3. 插件 ...

  6. OLED 驱动模块程序代码

    1.前言 作为嵌入式软件开发,可能经常会使用单片机连接驱动显示屏,实现人机交互的功能,通常可选择的有 OLED 和 LCD 等,其中相关驱动代码例程网上更是数不胜数. 本文介绍的是 OLED, 常见代 ...

  7. 使用了未经检查或不安全的操作。 有关详细信息, 请使用 -Xlint:unchecked 重新编译

  8. DBGRIDEH 底部多列 发现

    1.设置底部行数 2.点击footers 单独对每一行进行设置 3.单独对这两行 进行设置 5.看下辅助 所以用的时候可以这样用:WeiTopTradeShow.FieldColumns['top_x ...

  9. ASP.NET Core分布式项目实战(运行Consent Page)--学习笔记

    任务21:运行Consent Page 修改 Config.cs 中的 RequireConsent 为 true,这样登录的时候就会跳转到 Consent 页面 修改 ConsentControll ...

  10. Python-目录下相同格式的Excel文件合并

    最近在客户现场接到一个任务,需要将全国所有省份的数据进行合并.目录是分层级的,首先是省份目录.然后地级市目录.最里面是区县目录.需要将每个目录中的数据进行合并,然后添加4列数据,并将某一个列的数据进行 ...