C++ STL之 map 学习笔记
要是觉得内容枯燥,您可以点击左下角的播放按钮,让您在音乐的熏陶下愉快的阅读
本文总字数:7039
•何为 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.【std::map】
3.【C++中的STL中map用法详解】
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!