•何为 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. 从python3到python2的踩坑

    为什么要从py3到py2 背景:之前自学写过一些py3,而且我写的工具是基于python3来写的,但是公司项目是使用python2版本,希望已有工具或者新写的工具能同时在py2和py3上执行,所以记录 ...

  2. Couldn't launch Python exit code 9009

    Couldn't launch Python exit code 9009 start stable-diffusion-webui,发现,python 环境没有,我本地其实是已经安装完毕的,后来发现 ...

  3. 守护进程(Python)

    #__author__:Kelvin #date:2020/5/10 11:37 import time from multiprocessing import Process def son1(): ...

  4. HanLP — 词性标注

    词性(Part-Of-Speech,POS)指的是单词的语法分类,也称为词类.同一个类别的词语具有相似的语法性质 所有词性的集合称为词性标注集. 词性的用处 当下游应用遇到OOV时,可以通过OOV的词 ...

  5. 优化算法之梯度下降|Matlab实现梯度下降算法

    题目要求: 使用Matab实现梯度下降法 对于函数: min ⁡ f ( x ) = 2 x 1 2 + 4 x 2 2 − 6 x 1 − 2 x 1 x 2 \min f(x)=2 x_{1}^{ ...

  6. Java 将PDF转为PowerPoint (2行代码)

    通过编程实现PDF转PPT的功能,可以自动化转换过程,减少手动操作的工作量,并根据需要进行批量转换.将PDF文件转换为PPT文档后,可以利用PPT的丰富功能和动画效果,达到更好的演示效果. 在Java ...

  7. Linux的yum源配置总结

    本文总结归纳了一系列Linux系统的各种yum配置,虽然不一定是标准配置,但都是自己曾真实测过可用的. 1.RHEL6 本地 yum源配置 2.CentOS6 本地 yum源配置 3.OEL5 本地 ...

  8. 【译】VisualStudio 17.9预览3带来了令人兴奋的代码搜索改变

    随着 VisualStudio17.9预览版3的发布,我们为代码搜索(也称为 All-In-One Search)带来了一些令人兴奋的增强.自从我们上次更新搜索体验以来,我们一直在努力改进体验,并想出 ...

  9. C# 二十年语法变迁之 C# 2,C# 3 ,C# 4参考

    C# 二十年语法变迁之 C# 2,C# 3 ,C# 4参考 https://benbowen.blog/post/two_decades_of_csharp_i/ 自从 C# 于 2000 年推出以来 ...

  10. Python 爬虫方法总结

    实现爬虫的套路 准备URL 准备start_url url地址规律不明显,总数不确定 通过代码提取下一页的url 通过xpath提取 寻找url地址,部分参数在当前的响应中(比如当前页码数和总页码数在 ...