我们常常把map
称之为映射,就是将一个元素(通常称之为key键
)与一个相对应的值(通常称之为value
)关联起来,比如说一个学生的姓名(key)有与之对应的成绩(value),它们是一一对应的,就好像一把钥匙开一扇门,在map
中键是唯一的,也只有一个唯一的确定的值。
map
中的键是唯一的,但是multimap
则没有此限制
在C++中, map
提供了以下三种数据结构,其底层实现以及优劣如下表所示:
映射 | 底层实现 | 是否有序 | 数值是否可以重复 |
---|---|---|---|
std::map | 红黑树 | key有序 | key不可重复 |
std::multimap | 红黑树 | key有序 | key可重复 |
std::unordered_map | 哈希表 | key无序 | key不可重复 |
std::unordered_map
的key
值存储是无序的,底层实现为哈希表,查找速度更快,如果不需要排序而只是快速查找键对应的值,可以考虑使用。
std::map
和std::multimap
的底层实现是红黑树,它的key
值存储是有序的,如果需要对键值对进行自定义排序,可以考虑使用std::map
。
使用映射容器需要先引入头文件
和
// 引入 unordered_map 头文件,包含 unordered_map 类型
#include
// 引入map头文件,包含 map 类型和 multimap 类型
#include
想要声明map映射
关系,需要指定键的类型和值的类型
// // 声明一个整数类型映射到整数类型的无序映射
unordered_map<int, int> uMap;
// 声明一个将字符串映射到整数的 map,
map<string, int> myMap;
想要插入键值对key-value
,需要使用insert()
函数或者使用[]
操作符来插入。如果键不存在[]
操作符将会创建一个新的键值对,将其插入到map
中,并将其初始化为默认值(对于整数来说,默认值为0)
uMap[0] = 10;
uMap[1] = 20;
myMap["Math"] = 100;
myMap["english"] = 80;
和set
类似,可以使用find()
函数来检查某个键是否存在于map
中,它会返回一个迭代器,如果键存在,迭代器指向该键值对,否则指向map
的末尾
if (myMap.find("Math") != myMap.end()) {
// 键存在
} else {
// 键不存在
}
可以使用范围for循环
来遍历map
中的所有键值对,进行各种操作
for (const pair<int, int> &kv:umap) {
}
当使用范围for循环
遍历map
时,我们需要声明一个变量kv
来存储每个键值对,这个变量的类型通常为pair
类型。
const
用于声明一个不可修改的变量,这意味着一旦变量被初始化,就不能再修改其值。常量通常用大写字母表示。
因为 const 声明的变量一旦创建后就无法改变其值,所以必须初始化
const double PI = 3.1415926;
在这里const
表示你只能读取容器中的元素,而不能修改它们。
而pair
定义了kv
也就是键值对的数据类型是pair
,C++中的pair
类型会将两个不同的值组合成一个单元,常用于存储键值对,创建pair
的时候,也必须提供两个类型名,比如上面的pair
对象,两个值的类型都是int
,在使用时通过first
和second
成员来访问pair
中的第一个和第二个元素,它的first
成员存储键,second
成员存储值。
&
表示kv
是一个引用,而不是值拷贝,如果不使用引用的话,在每次迭代循环中都会创建一个新的pair
对象来复制键值对,这会导致不必要的内存分配和拷贝操作
代码的基础结构
#include
#include
using namespace std;
int main() {
int s, n, key, door, x;
cin >> s;
}
创建map容器,并在输入数据时将 key 和 door 输入到map中
while (s--) {
unordered_map<int, int> uMap;
cin >> n;
while (n--) {
cin >> key >> door;
uMap[key] = door;
}
设置一个flag
,用来标志是否找到了匹配的键值对
bool flag = true;
遍历map
,判断当前键值对中的值是否等于输入的值,如果等于,则将键输出并退出
for (const pair<int, int> &kv : uMap) {
// 检查当前键值对中的值是否等于x
if (kv.second == x) {
// 如果找到了匹配的键值对,将键kv.first输出到标准输出,并换行
cout << kv.first << endl;
flag = false;
break;
}
}
完整代码如下:
#include
#include
using namespace std;
int main() {
int s, n, key, door, x;
cin >> s;
while (s--) {
unordered_map<int, int> uMap;
cin >> n;
while (n--) {
cin >> key >> door;
uMap[key] = door;
}
cin >> x;
bool flag = true;
for (const pair<int, int> &kv : uMap) {
if (kv.second == x) {
cout << kv.first << endl;
flag = false;
break;
}
}
if (flag) cout << "Can't open the door." << endl;
}
}
C++11引入了范围for循环,用于方便地遍历容器中的元素,这种循环提供了一张简单的方式来迭代容器中的每个元素,而不需要显式地使用迭代器和索引。
for (类型 变量名 : 容器){
// 在这里使用一个变量名,表示容器中的每个元素是
}
比如下面的代码就表示使用范围for循环遍历一个容器
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (int num : numbers) {
std::cout << num < " ";
}
范围for循环不会修改容器中的元素,它只用于读取元素。如果需要修改容器中的元素,需要使用传统的for循环或其他迭代方式
此外,还可以使用auto
关键字来让编译器自动推断元素的类型,这样代码会更通用。
for (auto num : numbers) {
std::cout << num << " ";
}