今天的主题是什么?map(映射)!map(映射)!map(映射)!
pair类模板 
在开始学习map之前,先来看看pair。考虑到“键值对”并不是普通的类型数据,C++ STL标准库提供了pair类模板,专门用来将2个普通元素first和second(可以是任何已有的数据类型)创建成1个新元素<first, second>. 通过其构成的元素格式不难看出,使用pair类模板来创建“键值对”形成的元素非常合适。使用pair类模板需要增加头文件【#include <pair>】
pair的使用
// 创建一个空的pair对象p
pair<int, string> p;
// 创建一个空的pair对象p2并赋值(2022, "BigXMeng")
pair<int, string> p2(2022, "BigXMeng");
// 创建一个和p2一模一样的pair对象
pair<int, string> p3(p2);
// 使用make_pair()函数创建一个pair对象
pair<int, string> p4(make_pair(2022, "Liu Xianmeng"));
printf("%d %s\n", p.first, &p.second[0]);
printf("%d %s\n", p2.first, &p2.second[0]);
printf("%d %s\n", p3.first, &p3.second[0]);
printf("%d %s\n", p4.first, &p4.second[0]);
printf("p2 == p3 ? ");
if(p2 == p3) printf("true\n");
else printf("false\n");
map 
map概述
- map容器存储的都是pair对象,也就是用pair类模板创建的键值对。其中,各个键值对的键和值可以是任意的数据类型,包括C++基本数据类型(int、double等)、结构体或自定义类型。通常情况下,map容器中存储的各个键值对都选用string字符串作为键的类型。在使用map容器存储多个键值对的时候,会自动根据键值对中键的大小按照既定的规则进行排序。需要注意的是,使用map容器存储的各个键值对,键的值既不能重复也不能被修改。
- 使用map容器需要添加头文件【#include <map>】
创建map对象
// 创建一个空的map容器
map<string, char> m;
// 创建map容器的同时进行初始化数据
map<string, char> m2{{"BigXMeng", 'M'},{"zhangsan", 'F'}};
// 效果和m2的创建是一样的
map<string, char> m3{make_pair("BigXMeng", 'M'), make_pair("lisi", 'F')};
// 创建一个和m2数据完全一样的map
map<string, char> m4(m2);
验证map对存储的数据的排序(按照键的大小)
用map获取键值对的方法
map容器中存储的都是pair类型的键值对,在实际使用中map容器的场景中,经常要做的不是找到指定的键值对【pair对象】,而是从map中找到某个键对应的值。map容器提供了以下2种方法,可以直接获取map容器键指定的值:(1) m.[KEY] (2) m.at(KEY)
map<string, char> m{{"BigXMeng", 'M'},{"zhangsan", 'F'}};
char receive = m["BigXMeng"];
char receive2 = m.at("BigXMeng");
printf("char receive = %c\n", receive); // char receive = M
printf("char receive2 = %c", receive2); // char receive2 = M
添加数据和遍历数据
map<char, string> m;
m.insert(make_pair('f', "I ")); // 可以插入一个pair
// 可以插入一个存储pair的list
m.insert({make_pair('o', "enjoy "),make_pair('q', "learning ")});
m.insert({'a', "STL ~"}); // 可以插入一个二维空间
map<char,string> :: iterator it;
int i;
for(it=m.begin(), i=1; it!=m.end(); ++it,++i){
printf("pair%d : <\'%c\', \"%s\">\n", i, it->first, &it->second[0]);
/** [遍历结果如下]
* pair1 : <'a', "STL ~">
* pair2 : <'f', "I ">
* pair3 : <'o', "enjoy ">
* pair4 : <'q', "learning ">
*/
}
其他操作演示
printf("1 当前的map的size = %d\n", m.size());
printf("2 当前的map是否为空 = %s\n", m.empty()?"Yes":"No");
auto p1 = m.upper_bound('a'); // 返回第一个key大于'a'的pair迭代器
auto p2 = m.lower_bound('a'); // 返回第一个key大于或等于'a'的pair迭代器
printf("3 p1 = <\'%c\', \"%s\">\n", p1->first, &p1->second[0]);
printf("4 p2 = <\'%c\', \"%s\">\n", p2->first, &p2->second[0]);
m.clear(); // 清空map
printf("5 当前的map是否为空 = %s\n", m.empty()?"Yes":"No");
/** [打印结果如下]
* 1 当前的map的size = 3
* 2 当前的map是否为空 = No
* 3 p1 = <'o', "enjoy ">
* 4 p2 = <'a', "STL ~">
* 5 当前的map是否为空 = Yes
*/
multimap 
multimap 概述
- multimap相比于map可以存储多个键相同的键值对,正因如此,mutilmap不支持这两种方法取数据: (1) m.[KEY] (2) m.at(KEY) ;同时lower_bound(KEY)、upper_bound(KEY)、count(KEY)等方法比较常用
- 使用multimap需要包含头文件【#include <map>】
m.equal_range(val) 函数
multimap中可以插入相同的键,那么我们如何得知插入了多少个键值相同的元素呢?这个时候m.equal_range(val) 函数闪亮登场,它会返回一个pair类型的迭代器,其中的first指向包含val的所有元素范围的左边界,而second指向右边界。
一起来验证一下:
#include <bits/stdc++.h>
using namespace std;
int main(){
multimap<int, string> m;
m.insert(make_pair(8, "Big"));
m.insert(make_pair(6, "X1"));
m.insert(make_pair(6, "X2"));
m.insert(make_pair(2, "Meng"));
m.insert(make_pair(6, "X3"));
pair<multimap<int, string>::iterator, multimap<int, string>::iterator> pair = m.equal_range(6);
int i = 1;
for(multimap<int, string> :: iterator it = pair.first; it!=pair.second; ++it, ++i){
printf("第%d个键为6的m中的元素为:<%d, \"%s\">\n", i, it->first, &it->second[0]);
}
/* [打印遍历结果]
第1个键为6的m中的元素为:<6, "X1">
第2个键为6的m中的元素为:<6, "X2">
第3个键为6的m中的元素为:<6, "X3">
*/
printf("断点调式..");
return 0;
}
其他通用操作后续更新...
编程实战 
问题 1: 统计数字
题目描述
(时间限制: 1.000 Sec 内存限制: 64 MB)
某次科研调查时得到了n个自然数,每个数均不超过1500000000 (1.5×109)。已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。
输入
第1行是整数n,表示自然数的个数;
第2~n+1每行一个自然数。输出
共m行(m为n个自然数中不相同数的个数),按照自然数从小到大的顺序输出。每行输出两个整数,分别是自然数和该数出现的次数,其间用一个空格隔开。
样例输入 Copy
8 2 4 2 4 5 100 2 100样例输出 Copy
2 3 4 2 5 1 100 2提示
100%的数据满足:1≤n≤200000,每个数均不超过1.5×109。
问题分析和代码:
/**
* Created By Liu Xianmeng On 2022/11/30
* 【题目分析】
* 题目要求需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果
* 而 C++ STL的 map集合几乎可以完美地解决这个问题
* 当遍历到一个要记录的数,这个数在map中不存在时,则新建一个pair存入map
* 若map中已经存在该数的记录信息 则将返回的迭代器指向的pair的值+1
*/
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
scanf("%d", &n);
map<int, int> m; // 用map存要打印的数据
int num;
// 循环输入要记录的数字num
for(int i=1; i<=n; ++i){
scanf("%d", &num);
// 如果map中目前没有num的保存信息
if(m.find(num) == m.end()){
// 则新建一个pair并放入map
m.insert(make_pair(num, 1));
} else{ // 如果map中已经有num的保存信息
++(m.find(num)->second); // 则将找到的返回的迭代器指向的pair的值+1
}
}
// 打印结果
for(auto p : m){
printf("%d %d\n", p.first, p.second);
}
return 0;
}
谢谢读取 ~