map映射

Ⅰ.map

map可以翻译为映射,是 STL 中常用的容器。其实,数组就是一种映射。比如 int a[100]; 定义了一个 int 到 int 的映射,而 a[5] = 25; 就是把 5 映射到 25 。数组总是将 int 类型映射到其他基本类型(称为数组的基本型),这同时也带了一个问题,有时候希望把 string 映射成一个 int ,数组就不方便了。这时候就可以使用 map,map 可以将任何基本类型(包括 STL 容器)映射到任何基本类型(包括 STL 容器)。
map 的用途至少有以下三种情形:

  • 需要建立字符(串)与整数之间的映射,使用 map 可以减少代码量。
  • 判断大整数(比如几千位)或者其他类型数据是否存在,可以把 map 当布尔类型数组使用(哈希表)。
  • 字符串与字符串之间的映射。

要使用 map ,必选先添加 map 头文件,即 #include<map>,同时必须要有 using namespace std。
定义一个 map 的方法如下:
map<typename1,typename2> name;
其中,typename1 是映射前的类型(键key),typename2是映射后的类型(值value),name为映射的名字。
普通 int 数组 a 就是 map<int,int> a。而如果是字符串到整型的映射,就必须使用string而不能使用char,即 map<string,int> a,map的键和值也可以 STL 容器,比如 map<set,string> mp。当然需要注意的是:map的键是唯一的。

Ⅱ. map的访问

访问 map 的元素有两种方式,一种是通过下标访问;另一种是通过迭代器访问。
① 通过下标访问就像普通的数组元素访问,例如先定义 map<char,int> mp,然后就可以通过 mp['c'] 的方式来访问它对应的元素,如 mp['c'] = 124。
② 通过迭代器访问,先做如下定义:
map<typename1,typename2>::iterator it;//iterator ['it reit ]
因为 map 的每一对映射都有两个typename,所以使用 it->first 来访问键,而使用 it->second 来访问值。例如:

#include<bits/stdc++.h>
using namespace std;

int main(){
    map<char,int> mp;
    mp['m'] = 20;
    mp['r'] = 30;
    mp['a'] = 40;
    for(map<char,int>::iterator it = mp.begin(); it != mp.end();it++){
        cout<<it->first<<" "<<it->second<<endl;
    }
    return 0;
}

程序输出如下:
a 40
m 20
r 30
可以看出,map在建立映射的同时,会自动实现按照键从小到大排序。这是因为map内部是使用“红黑树”实现的(set也是)。

从c++更新以来,有了新的关键字 auto,也可以实现 map 遍历。
注意:dev-c++编译时默认使用的是C98标准,所以才会出错,如需支持C11标准,只需在编译选项中修改配置参数。
在编译器下面的编译时加入以下命令前打勾,并在输入框内,输入-std=c++11。即可。

#include<bits/stdc++.h>
using namespace std;

int main(){
    map<char,int> mp;
    mp['m'] = 20;
    mp['r'] = 30;
    mp['a'] = 40;
    for(auto i:mp){
        cout<<i.first<<" "<<i.second<<endl;
    }
    return 0;
}

Ⅲ. map的常用函数

map的常用函数有find、size、erase、clear、count等。
① find() 和 size()
find(key)是返回键为key的映射的迭代器,时间复杂度为\(O(\log_2N\)),N为map中映射的对数。size()用来获得map中映射的对数,时间复杂度为O(1)。例如,以下一段代码输出“3 b 30”。

#include<bits/stdc++.h>
using namespace std;

int main(){
    map<char,int> mp;
    mp['a'] = 20;
    mp['b'] = 30;
    mp['c'] = 40;
    printf("%d ",mp.size());
    map<char,int>::iterator it = mp.find('b');
    printf("%c %d",it->first,it->second);
    return 0;
}

② erase( )
erase( )可以删除单个元素,也可以删除一个区间内的所有元素。删除单个元素可以使用erase(it),其中it是为要删除的元素的迭代器,时间复杂度是O(1)。也可以使用erase(key),其中key为要删除的映射的键,时间复杂度为\(O(\log_2N\))。例如,以下一段代码输出“a 20 c 40”。

#include<bits/stdc++.h>
using namespace std;

int main(){
    map<char,int> mp;
    mp['a'] = 20;
    mp['b'] = 30;
    mp['c'] = 40;
    map<char,int>::iterator it = mp.find('b');
    mp.erase(it);//或者把两句语句改成mp.erase('b');总的时间复杂度一样。
    for(map<char,int>::iterator it = mp.begin();it != mp.end();it++)
        printf("%c %d ",it->first,it->second);
    return 0;
}

删除一个区间内的所有元素用erase(first,last)。其中,first为区间的起始迭代器;last为区间的末尾迭代器的下一个地址,也就是左闭右开的区间[first,last]。其中时间复杂度为O(last-first)。
例如,以下一段代码输出“a 20”。

#include<bits/stdc++.h>
using namespace std;

int main(){
    map<char,int> mp;
    mp['a'] = 20;
    mp['b'] = 30;
    mp['c'] = 40;
    map<char,int>::iterator it = mp.find('b');
    mp.erase(it,mp.end());
    for(map<char,int>::iterator it = mp.begin();it != mp.end();it++)
        printf("%c %d ",it->first,it->second);
    return 0;
}

③ clear()
clear()用来清空map,时间复杂度为O(n)。

④ count(key)
由于map不包含重复的key,因此m.count(key)取值为0,或者1,表示是否包含。
在map中,由key查找value时,首先要判断map中是否包含key。
如果不检查,直接返回map[key],可能会出现意想不到的行为。如果map包含key,没有问题,如果map不包含key,使用下标有一个危险的副作用,会在map中插入一个key的元素,value取默认值,返回value。也就是说,map[key]不可能返回null。

Ⅳ.例题

例1

题目描述
\(STL map\) 基本练习题。
我们所在的学校刚刚完成期末考试,由于数据量很大,老师希望你能帮助他完成以下任务。
提供 \(n\) 组数据,每个数据由字符串和浮点数构成,两者使用空格隔开,字符串中间不会出现空格。表示某人的期末成绩。
例如:\(tom\ 95.3\),表示 \(tom\) 的期末成绩为 \(95.3\) 分。
家长需要根据孩子的名字来查询成绩。比如输入 \(tom\) 将得到 \(95.3\)
输入格式
第一行,两个数组\(n(1≤n≤10^5)\)\(q(1≤q≤10^5)\)
其后 \(n\) 行,表示有 \(n\) 个孩子的成绩。每行由字符串和浮点数构成,两者使用空格隔开,字符串中间不会出现空格。表示 \(key\) 为字符串,\(value\) 为浮点数。字符串不会超过 \(14\)
其后 \(q\) 行,表示有 \(q\) 个查询。每行为一个字符串,表示要查询的孩子名字。保证每个孩子都有成绩。保证每次查询都有对应的结果。
输出格式
一共有 \(q\) 行,每行一个浮点数,保留 \(2\) 位小数点精度。
输入样例1

7 7
tom 95.499
jerry 98.328
alice 78.253
beta 100
gamma 53.2
delta 99.899
xita 35.4392
xita
tom
alice
jerry
gamma
delta
beta

输出样例1

35.44
95.50
78.25
98.33
53.20
99.90
100.00

数据范围
对于 \(30\%\) 的数据,\(n(1≤n≤100)\)\(q(1≤q≤100)\)

对于 \(60\%\) 的数据,\(n(1≤n≤10^4)\)\(q(1≤q≤10^4)\)

对于 \(100\%\) 的数据,\(n(1≤n≤10^5)\)\(q(1≤q≤10^5)\)

例2

题目描述
\(STL map\) 基本练习题。
我们所在的学校刚刚完成期末考试,由于数据量很大,老师希望你能帮助他完成以下任务。
提供 \(n\) 组数据,每个数据由字符串和浮点数构成,两者使用空格隔开,字符串中间不会出现空格。表示某人的期末成绩。
例如:\(tom\ 95.3\) ,表示 \(tom\) 的期末成绩为 \(95.3\) 分。
家长需要根据孩子的名字来查询成绩。比如输入 \(tom\) 将得到 。但是这次混入了一些非本校的家长,他们想搞坏我们的系统,这些家长输入的孩子是找不到的,碰到这样的情况,输出 \(-1\)
输入格式
第一行,两个数字 n (1≤n≤10^5) 和 q (1≤n≤10^5)。
其后 n 行,表示有 n 个孩子的成绩。每行由字符串和浮点数构成,两者使用空格隔开,字符串中间不会出现空格。表示 key 为字符串,value 为浮点数。字符串长度不会超过 。
其后 q 行,表示有 q 个查询。每行为一个字符串,表示要查询的孩子名字。如果找不到这个孩子,成绩输出-1 。

输出格式
一共有 \(q\) 行,每行一个浮点数,保留 \(1\) 位小数点精度。

输入样例1

7 10
tom 95.499
jerry 98.328
alice 78.253
beta 100
gamma 53.2
delta 99.899
xita 35.4392
xita
xi
tom
to
alice
jerry
gamma
delta
deta
beta

输出样例1

35.4
-1
95.5
-1
78.3
98.3
53.2
99.9
-1
100.0

数据范围
对于 \(30\%\) 的数据,\(n(1≤n≤100)\)\(q(1≤q≤100)\)

对于 \(60\%\) 的数据,\(n(1≤n≤10^4)\)\(q(1≤q≤10^4)\)

对于 \(100\%\) 的数据,\(n(1≤n≤10^5)\)\(q(1≤q≤10^5)\)

例3

题目描述
给出一串正整数数列以及一个正整数 \(C\),要求计算出所有满足 \(A−B=C\) 的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。
第一行,两个正整数 \(N,C\)
第二行,\(N\) 个正整数,作为要求处理的那串数。

输出格式
一行,表示该串正整数中包含的满足 \(A - B = C\) 的数对的个数。

输入样例1

4 1
1 1 2 3

输出样例1

3

数据范围
对于 \(75\%\) 的数据,\(1≤N≤2000\)
对于 \(100\%\) 的数据,\(1≤N≤2×10^5\)\(1≤a_i≤2^{30}\)\(1≤C≤2^{30}\)

例4

题目描述
输入一个仅包含小写英文字母字符的字符串 \(s\),定义“相邻字符对”为下标相邻的两个字符。
比如 s 为 ababba 时,一共有五对相邻字符对,分别为:abbaabbbba
现在需要输出出现次数最多的相邻字符对,如果有多个,则按照字典序依次输出。
输入格式
输入第一行为一个字符串 s。
输出格式
输出若干行,每行都是一对字符对,即所有出现次数最多的字符对。按照字典序顺序输出。

输入样例1

ababba

输出样例1

ab
ba

样例输入2

edcba

样例输出2

ba
cb
dc
ed

数据范围
∣s∣ 表示字符串 s 的长度
对于 \(60\%\) 的数据:1≤∣s∣≤100;
对于 \(100\%\) 的数据:1≤∣s∣≤100000。

例5

题目描述
大多数纵横填字谜迷都习惯于拼字游戏——一组单词在不同的字母中有相同的字母——例如OPTS、SPOT、STOP、POTS和POST。然而,有些单词没有这个属性,无论你如何重新排列它们的字母,你都不能组成另一个单词。这些单词被称为字谜,例如QUIZ。
输入一些单词,找出所有满足如下条件的单词: 该单词不能通过字母重排,得到输入文本中的另一个单词。
在判断是否满足条件时,字母不区分大小写,但在输出时应保留输入中的大小写,按字典序进行排序。(所有大写字母在所有小写字母的前面)
输入格式
输入将由一系列行组成。行的长度不能超过80个字符,但可以包含任意数量的单词。单词最多由20个大写和/或小写字母组成,并且不会在各行之间中断。单词周围可以自由出现空格,同一行中至少有一个空格分隔多个单词。请注意,包含相同字母但大小写不同的单词被视为相互之间的字谜,因此“tIeD”和“EdiT”是字谜。文件将以一行结束,该行由单个“#”组成
输出格式
输出将由一系列行组成。每行将包含一个单词,该单词在输入字典中是相对的字谜。单词必须按词典(区分大小写)顺序输出。总是会有至少一个相对的字谜。

样例输入1

ladder came tape soon leader acme RIDE lone Dreis peat
ScAlE orb eye Rides dealer NotE derail LaCeS drIed 
noel dire Disk mace Rob dries
#

样例输出1

Disk
NotE
derail
drIed
eye
ladder
soon
posted @ 2022-10-13 21:27  程易。  阅读(1094)  评论(0)    收藏  举报