C++知识点总结(33):STL(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 xy=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 110 之间的由大写字母构成的字符串。

输出描述

输出进入牛棚次数最多的一组牛的进入次数。

样例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 1N1000

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;
}
  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值