AI智能
改变未来

C++ STL之 map 学习笔记

•何为 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));//已存在\"张三\"数据,该插入操作不执行:张三-18cout << mymap[\"张三\"] << endl;mymap[\"张三\"] = 180;//覆盖:张三-180cout << 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;elsecout << \"张三查找失败\" << endl;if (mymap.count(\"张四\") > 0)cout << \"张四查找成功\" << endl;elsecout << \"张四查找失败\" << 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;elsecout << \"张三查找失败\" << endl;it = mymap.find(\"张四\");if (it != mymap.end())cout << \"张四查找成功,年龄为:\" << it->second << endl;elsecout << \"张四查找失败\" << 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;elsecout << \"张三查找失败\" << endl;it = mymap.find(\"张四\");if (it != mymap.end())cout << \"张四查找成功,年龄为:\" << it->second << endl;elsecout << \"张四查找失败\" << 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用法详解】

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » C++ STL之 map 学习笔记