map 映射
一、意义
1. 映射的概念
映射(mapping)
键(key
)与值(value
)的对应关系。
map
容器
一个STL
中常用的容器,可以将任何有序的类型(基本类型、string
)映射到任何类型(基本类型、string
、结构体、STL
容器)。
2. map 的特点
- 动态存储空间
- 插入、删除、查找效率高
- 键与值类型定义灵活
- 适用于判断范围较大的整数(例如在桶排序中)或者其他类型的数据(例如
string
)是否存在,以及需要建立的字符(串)与其他数据类型之间的映射
二、map 相关程序
1. 定义
定义格式:map <键类型, 值类型> 容器名;
例如:
#include <map>
map <string, string> m;
2. 初始化
初始化格式:map <键类型, 值类型> 容器名{{键1, 值1}, {键2, 值2}, ...};
#include <map>
map <string, string> m{{"a", "A"}, {"b", "B"}}; // 一定注意!没有等号!!
3. 赋值 & 访问
m["a"] = "A";
m["a"] = "B"; // 值会被覆盖
cout << m["a"]; // 输出: B
cout << m["b"]; // 输出空字符串
4. 拷贝
#include <map>
map <string, string> m2(m);
5. 所有操作
方法 | 功能 |
---|---|
mp[key] = value; | 修改 key 对应的 value ,如果不存在则创建 |
mp.insert({key1, value1}, {key2, value2}); | 插入纯新的键值对(不能更新){key1, value1} 和 {key2, value2} |
mp.emplace(key, value) | 插入纯新的键值对(不能更新){key, value} |
mp.erase(key); | 根据键删除键值对 |
mp.clear(); | 删除所有元素 |
mp.begin() | 返回指向 map 头部的迭代器 |
mp.end() | 返回指向 map 尾部的下一个位置的迭代器 |
mp.size() | 返回 map 中键值对的个数 |
mp.empty() | 判断是否为空 |
mp.find(key) | 获得指向键 key 的迭代器,如果未找到返回 mp.end() |
mp.count(key) | 查看指定键 key 是否出现,出现为
1
1
1,否则为
0
0
0 |
三、迭代器
1. 定义
#include <map>
map <string, string> m{{"a", "A"}};
auto it = m.begin();
2. 遍历
for (auto it = m.begin(); it != m.end(); it++)
{
cout << it->first << " " it->second << endl;
}
3. 所有操作
方法 | 功能 |
---|---|
it->first | 返回当前迭代器指向的键 |
it->second | 返回当前迭代器指向的值 |
mp.lower_bound(key) | 返回第一个键值大于等于 key 的迭代器 |
mp.upper_bound(key) | 返回第一个键值大于 key 的迭代器 |
四、例题
1. 登录注册
1.1 审题
做一个登录的功能,可以实现输入一个用户名,如果用户名在数据库里面已经用过了,那么将会跟上一个后缀。
1.2 参考答案
#include <iostream>
#include <string>
#include <map>
using namespace std;
int n;
map <string, int> m; // 键: 名字 值: 出现的次数
string s;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> s;
if (m[s] == 0) // 未出现
{
cout << "OK\n";
m[s] = 1;
}
else
{
cout << s << m[s] << endl;
m[s]++;
}
}
return 0;
}
2. XY 数对
2.1 审题
给定一个正整数数列 a[]
以及一个正整数
z
z
z,要求计算出所有满足
x
−
y
=
z
x-y=z
x−y=z 的数对的个数。
2.2 参考答案
#include <iostream>
#include <map>
using namespace std;
int n, z, x;
long long a[200005];
map <long long, long long> m; // 键: 数 值: 出现的次数
int main()
{
cin >> n >> z;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
m[a[i]]++;
}
for (int i = 1; i <= n; i++)
{
sum += m[a[i] - z];
}
cout << sum;
return 0;
}
3. 记录保存
3.1 审题
题目描述
农夫约翰一直在详细记录奶牛进入牛棚挤奶的情况。每小时会有一组三头牛进入牛棚产奶,约翰会记录他们的名字。例如,在5个小时内,他可能会记录下如下列表,每行对应进入牛棚的一组牛:
BESSIE ELSIE MATILDA FRAN BESSIE INGRID BESSIE ELSIE MATILDA MATILDA INGRID FRAN ELSIE BESSIE MATILDA
约翰发现同一组奶牛可能会多次出现在他记录的名单中,在上面的例子中,
BESSIE ELSIE MATILDA
这个组合出现了 3 3 3 次(尽管约翰不一定每次都按同样的顺序记录它们的样子),请帮助约翰计算进入牛棚次数最多的一组牛的进入次数。
输入描述
第一行包含整数 N N N。
接下来 N N N 行,每行都包含一组三头牛的名字,每个名字都是一个长度在 1 − 10 1-10 1−10 之间的由大写字母构成的字符串。
输出描述
输出进入牛棚次数最多的一组牛的进入次数。
样例1
输入
5 BESSIE ELSIE MATILDA FRAN BESSIE INGRID BESSIE ELSIE MATILDA MATILDA INGRID FRAN ELSIE BESSIE MATILDA
输出
3
提示
1 ≤ N ≤ 1000 1\le N \le1000 1≤N≤1000
3.2 参考答案
#include <iostream>
#include <algorithm>
#include <string>
#include <map>
using namespace std;
int maxn;
int n;
string s[5];
string team;
map <string, int> m;
int main()
{
cin >> n;
while (n--)
{
cin >> s[1] >> s[2] >> s[3];
sort(s+1, s+4);
team = s[1] + ' ' + s[2] + ' ' + s[3];
m[team]++;
}
for (auto it = m.begin(); it != m.end(); it++)
{
maxn = max(maxn, it->second);
}
cout << maxn;
return 0;
}
4. 家谱
4.1 审题
题目描述
现代的人对于本家族血统越来越感兴趣。给出充足的父子关系,请你编写程序找到某个人的最早的祖先。
输入由多行组成,首先是一系列有关父子关系的描述,其中每一组父子关系中父亲只有一行,儿子可能有若干行,用#name
的形式描写一组父子关系中的父亲的名字,用+name
的形式描写一组父子关系中的儿子的名字;接下来用?name
的形式表示要求该人的最早的祖先;最后用单独的一个$
表示文件结束。
输入描述
按照输入文件的要求顺序,求出每一个要找祖先的人的祖先,格式为:本人的名字 + + + 一个空格 + + + 祖先的名字 + + + 回车。
输出描述
规定每个人的名字都有且只有6个字符,而且首字母大写,且没有任意两个人的名字相同。最多可能有 1 0 3 10^3 103 组父子关系,总人数最多可能达到 5 × 1 0 4 5\times10^4 5×104 人,家谱中的记载不超过 300 300 300 代。
样例1
输入
#George +Rodney #Arthur +Gareth +Walter #Gareth +Edward ?Edward ?Walter ?Rodney ?Arthur $
输出
Edward Arthur Walter Arthur Rodney George Arthur Arthur
4.2 参考答案
#include <iostream>
#include <string>
#include <map>
using namespace std;
char c;
map <string, string> m; // 键: 儿子 值: 爸爸
string s, father;
int main()
{
while (cin >> c && c != '$')
{
cin >> s;
if (c == '#')
{
father = s;
}
if (c == '+')
{
m[s] = father;
}
if (c == '?')
{
string olds = s;
while (m.find(olds) != m.end()) // 一直找爸爸
{
olds = m[olds];
}
cout << s << ' ' << olds << endl;
}
}
return 0;
}