1、写在前面
大家好,今天文章的内容是:
- map容器
2、内容
2.1、介绍
map
类属于关联式容器,可用于存储和检索集合中的数据元素。
备注:
- 集合中的每个数据元素均为一种映射关系,是一种包含键和数据值的元素对。简单来说,每个
map
元素都是一个键值对; - 键具有唯一性,在
map
中不能出现重复的键,每个键都是独一无二的; - 键是常量,无法修改,我们只能修改键对应的数据值;
2.2、map类
(1) 语法
map类的语法如下:
template <class Key,
class T,
class Traits = less<Key>,
class Allocator = allocator<pair <const Key, T>>>
class map;
(2) 参数
Key
Key
指的是在map
中存储的键的数据类型;
T
T
指的是map
中键对应的元素值的数据类型;
Traits
Traits
是一种提供函数对象的类型,该函数对象将两个元素值作为排序键进行比较,用于指定map
中的排序规则;
备注:
Traits
属于可选参数- 默认值为
less<key>
,即升序。 - 也可以设置为
greater<key>
,即降序。
Allocator
Allocator
是一种表示分配器对象的类型。
备注:
Allocator
是可选参数- 默认值为
allocator<pair<const Key, T> >
- 该分配器对象封装了有关映射
map
的内存分配和解除分配的详细信息。
(3) 元素
在使用map
之前,我们需要清楚,map
中的每个元素,其数据类型是什么?
来看看map
中元素的定义语句:
typedef pair<const Key, T> value_type;
也就是说,map
中存储的元素,其数据类型就是value_type
。
map
容器存储的元素都是pair
对象,其利用了pair
类来创建键值对,其中各个键值对的键和值都可以是任意数据类型,包括C++
基本数据类型(如int
、double
等)、结构体或自定义类等。
2.3、创建map容器
(1) 导入头文件
因为map
容器定义在<map>
头文件中,并位于std
命名空间中。
所以我们在使用map
容器之前需要导入以下代码:
#include <map>
using namespace std;
在导入头文件后,就可以使用map
容器了。
(2) 举例一
代码:
map <int, int> m1;
上述代码创建了一个空的map
容器m1
。此时容器中是没有存储任何键值对的。其中键key
和值value
的数据类型都是int
类型,并且使用了默认的排序规则(升序:less<Key
)
(3) 举例二
下面的程序创建了一个空map
容器,并向其中插入了五个元素。每个元素的数据类型都是pair<int, int>
。
输出map
中的内容后,可以发现,虽然在插入数据元素时键是无序的,但是在map内部会自动按照指定的键比较函数来按顺序排列键。这里使用的是默认值less<key>
,即升序。
代码:
#include <iostream>
#include <map>
using namespace std;
typedef pair<int, int> myPair;
void printMap(const map<int, int>& m) {
cout << "容器中的内容为:" << endl;
cout << "key\tvalue" << endl;
for (auto i : m) {
cout << i.first << "\t" << i.second << endl;
}
}
int main() {
// 创建一个空容器 m2
map <int, int> m2;
// 插入五个元素
m2.insert(myPair(5, 55));
m2.insert(myPair(1, 11));
m2.insert(myPair(3, 33));
m2.insert(myPair(2, 22));
m2.insert(myPair(4, 44));
// 输出
cout << "m2";
printMap(m2);
return 0;
}
运行结果:
m2容器中的内容为:
key value
1 11
2 22
3 33
4 44
5 55
(4) 举例三
创建一个map
容器并复制其他map
容器中的内容。
代码:
#include <iostream>
#include <map>
using namespace std;
typedef pair<int, int> myPair;
void printMap(const map<int, int>& m) {
cout << "容器中的内容为:" << endl;
cout << "key\tvalue" << endl;
for (auto i : m) {
cout << i.first << "\t" << i.second << endl;
}
}
int main() {
// 创建一个空容器 m1
map <int, int> m1;
// 插入五个元素
m1.insert(myPair(5, 55));
m1.insert(myPair(1, 11));
m1.insert(myPair(3, 33));
m1.insert(myPair(2, 22));
m1.insert(myPair(4, 44));
// 创建一个容器 m3 并用 m2 进行初始化
map<int, int> m3(m1);
// 输出
cout << "m3";
printMap(m3);
return 0;
}
运行结果:
m3容器中的内容为:
key value
1 11
2 22
3 33
4 44
5 55
(5) 举例四
创建一个map
容器并用其他map
容器中指定区间上的元素来初始化。
代码:
#include <iostream>
#include <map>
using namespace std;
typedef pair<int, int> myPair;
void printMap(const map<int, int>& m) {
cout << "容器中的内容为:" << endl;
cout << "key\tvalue" << endl;
for (auto i : m) {
cout << i.first << "\t" << i.second << endl;
}
}
int main() {
// 创建一个空容器 m1
map <int, int> m1;
// 插入五个元素
m1.insert(myPair(5, 55));
m1.insert(myPair(1, 11));
m1.insert(myPair(3, 33));
m1.insert(myPair(2, 22));
m1.insert(myPair(4, 44));
// 输出
cout << "m1";
printMap(m1);
cout << "\n取m1中指定区间 [1, 3) 内的元素来初始化 m4\n" << endl;
// 创建两个迭代器对象
map<int, int>::const_iterator first, last;
// first指向 m1 的第一个元素
first = m1.begin();
// last 指向 m1 的第三个元素
last = m1.begin();
last++;
last++;
// 创建新容器 m4并 用原先的容器 m1 中指定的区间来初始化 m4
map <int, int> m4(first, last);
// 输出
cout << "m4";
printMap(m4);
return 0;
}
运行结果:
m1容器中的内容为:
key value
1 11
2 22
3 33
4 44
5 55
取m1中指定区间 [1, 3) 内的元素来初始化 m4
m4容器中的内容为:
key value
1 11
2 22
(6) 举例五
创建并初始化map
容器。
代码:
#include <iostream>
#include <map>
using namespace std;
typedef pair<int, int> myPair;
void printMap(const map<int, int>& m) {
cout << "容器中的内容为:" << endl;
cout << "key\tvalue" << endl;
for (auto i : m) {
cout << i.first << "\t" << i.second << endl;
}
}
int main() {
// 创建容器 m5 并初始化
map <int, int> m5{{3, 33}, {1, 11}, {2, 22}};
// 输出
cout << "m5";
printMap(m5);
return 0;
}
运行结果:
m5容器中的内容为:
key value
1 11
2 22
3 33
2.4、成员函数
map
的成员函数有很多,这里记录几个常用的。
at
at()
函数用于查找给定键所对应的元素值。
语法如下:
T& at(const Key& key);
const T& at(const Key& key) const;
举个例子:
#include <iostream>
#include <map>
using namespace std;
void printMap(const map<char, int>& m) {
cout << "容器中的内容为:" << endl;
cout << "key\tvalue" << endl;
for (auto i : m) {
cout << i.first << "\t" << i.second<< endl;
}
cout << '\n';
}
int main() {
map<char, int> myMap{ {'b',76}, {'a', 98}, {'c', 59} };
cout << "myMap";
printMap(myMap);
cout << "myMap.at('a') == " << myMap.at('a') << '\n' << endl;
cout << "myMap.at('b') == " << myMap.at('b') << '\n' << endl;
cout << "myMap.at('c') == " << myMap.at('c') << '\n' << endl;
return (0);
}
运行结果:
myMap容器中的内容为:
key value
a 98
b 76
c 59
myMap.at('a') == 98
myMap.at('b') == 76
myMap.at('c') == 59
begin
begin()
函数用于返回一个迭代器对象,其指向map
中的第一个元素。
语法如下:
iterator begin();
const_iterator begin() const;
举个例子:
#include <iostream>
#include <map>
using namespace std;
int main() {
map<int, int> m;
m.insert ( pair<int, int>( 1, 100 ) );
m.insert ( pair<int, int>( 2, 200 ) );
m.insert ( pair<int, int>( 3, 300 ) );
map<int, int>::iterator m_it = m.begin();
cout << "map中的第一个键为:" << m_it->first << ",其对应的值为:" << m_it->second << endl;
m_it++;
m_it++;
cout << "map中的第三个键为:" << m_it->first << ",其对应的值为:" << m_it->second << endl;
return (0);
}
运行结果:
map中的第一个键为:1,其对应的值为:100
map中的第三个键为:3,其对应的值为:300
end
end()
函数用于返回末尾元素之后的迭代器对象。
注意,返回的双向迭代器是指向容器最后一个元素的后一个位置。
备注:
如果映射为空,则map::end() == map::begin()
clear
clear()
函数用于清除map
中的所有元素。
语法如下:
void clear();
contains
contains()
函数用于判断map
中是否含有指定键的元素。如果找到该元素,则返回true
,否则返回false
。
备注:
- 使用需知,
contains()
属于C++20
中新增的功能。
语法如下:
bool contains(const Key& key) const;
template<class K> bool contains(const K& key) const;
emplace
emplace()
函数可用于向map
内插入构造的元素,不执行复制操作或移动操作。
语法如下:
template <class... Args>
pair<iterator, bool> emplace(Args&&... args);
说明:
- 这个函数的返回值是:
pair<iterator, bool>
,假设返回的是pr
- 如果新元素插入成功,则
pr.second
,即bool
值为true
- 如果新元素插入失败,则
pr.second
,即bool
值为false
。什么情况下会插入失败?如果插入的元素的键key
在map
中已经存在了,那么此时插入操作返回值的bool
值为false
- 而
pr.first
则是一个迭代器对象。如果bool
值为true
,则该迭代器对象pr.first
指向的是新插入的元素。如果bool
值为false
,则该迭代器对象pr.first
指向的是现有的元素。
举个例子:
#include <iostream>
#include <map>
#include <string>
using namespace std;
template <typename M> void print(const M& m) {
cout << "容器内容为:\nkey\tvalue\n";
for (const auto& i : m) {
cout << i.first << '\t' << i.second << endl;
}
cout << endl;
}
template <typename T> void judge(const T& e) {
cout << "正在修改map...";
if ( e.second == true){
cout << "修改成功!" << endl;
}
else{
// 解引用,获取该迭代器对象 e 指向的 map 元素
auto p = *e.first;
cout << "添加元素失败!\n"
<< "欲添加的元素中,键值(" << p.first << ")已经存在了" << endl;
}
cout << endl;
}
int main() {
map <int, string> m1{{3, "叁"}, {1, "壹"}, {2, "贰"}};
print(m1);
auto re = m1.emplace(4, "肆");
judge(re);
print(m1);
re = m1.emplace(4, "四");
judge(re);
print(m1);
return 0;
}
运行结果:
容器内容为:
key value
1 壹
2 贰
3 叁
正在修改map...修改成功!
容器内容为:
key value
1 壹
2 贰
3 叁
4 肆
正在修改map...添加元素失败!
欲添加的元素中,键值(4)已经存在了
容器内容为:
key value
1 壹
2 贰
3 叁
4 肆
empty
empty()
函数用于判断该map
容器是否为空。如果map
为空,则返回true
,否则返回false
语法如下:
bool empty() const;
erase
erase()
函数用于从map
中的指定位置删除单个元素,或删除指定范围内的元素,或者删除与指定键匹配的map
元素。
语法如下:
iterator erase(const_iterator Where);
iterator erase(const_iterator First, const_iterator Last);
size_type erase(const key_type& Key);
举个例子:
#include <iostream>
#include <map>
#include <string>
using namespace std;
template <typename M> void print(const M& m) {
cout << "容器内容为:\nkey\tvalue\n";
for (const auto& i : m) {
cout << i.first << '\t' << i.second << endl;
}
cout << endl;
}
int main() {
// 创建四个容器
map<int, string> m0{{1, "A"}, {4, "D"}, {2, "B"}, {5, "E"}, {3, "C"}};
map<int, string> m1{{1, "A"}, {4, "D"}, {2, "B"}, {5, "E"}, {3, "C"}};
map<int, string> m2{{1, "A"}, {4, "D"}, {2, "B"}, {5, "E"}, {3, "C"}};
map<int, string> m3{{1, "A"}, {4, "D"}, {2, "B"}, {5, "E"}, {3, "C"}};
cout << "原先的";
print(m0);
// 1. 调用 erase(const_iterator Where)
m1.erase(m1.begin());
cout << "删除第一个元素后,";
print(m1);
// 2. 调用 erase(const_iterator First, const_iterator Last);
map<int, string>::const_iterator first = m2.begin();
map<int, string>::const_iterator last = m2.begin();
last++;
last++;
m2.erase(first, last);
cout << "删除指定区间[1, 3)内的元素后,";
print(m2);
// 3. 调用 erase(const key_type& Key)
m3.erase(3);
cout << "删除指定键为3的元素后,";
print(m3);
return 0;
}
运行结果:
原先的容器内容为:
key value
1 A
2 B
3 C
4 D
5 E
删除第一个元素后,容器内容为:
key value
2 B
3 C
4 D
5 E
删除指定区间[1, 3)内的元素后,容器内容为:
key value
3 C
4 D
5 E
删除指定键为3的元素后,容器内容为:
key value
1 A
2 B
4 D
5 E
find
find()
函数可用于查找与给定键匹配的元素。
语法如下:
iterator find(const Key& key);
const_iterator find(const Key& key) const;
说明:
- 如果找到和给定的键匹配的元素,则返回的迭代器对象会指向该元素。
- 但如果在map中找不到与键匹配的元素,则返回的迭代器对象指向的位置和
map::end()
指向的位置是一样的。
举个例子:
#include <iostream>
#include <map>
using namespace std;
template <typename M> void print(const M& m) {
cout << "容器内容为:\nkey\tvalue\n";
for (const auto& i : m) {
cout << i.first << '\t' << i.second << endl;
}
cout << endl;
}
template <typename M> void findVal(const M& m, int& value) {
if(m.find(value) == m.end()) {
cout << "查找失败!找不到键为 " << value << " 的元素" << '\n' << endl;
} else {
cout << "找到了!容器里键为 " << value << " 的元素对应的值为 " << m.at(value) << '\n' << endl;
}
}
int main() {
// 创建四个容器
map<int, char> m{{1, 'A'}, {4, 'D'}, {2, 'B'}, {5, 'E'}, {3, 'C'}};
print(m);
int v1 = 4;
int v2 = 6;
findVal(m, v1);
findVal(m, v2);
return 0;
}
运行结果:
容器内容为:
key value
1 A
2 B
3 C
4 D
5 E
找到了!容器里键为 4 的元素对应的值为 D
查找失败!找不到键为 6 的元素
size
size()
函数用于返回map
中的元素数量。
语法如下:
size_type size() const;
2.5、小结
有关map
的小结:
map
是一种大小可变的关联式容器,其中存储的每个元素都包含一个映射关系,可用来基于关联键高效的检索对应的元素值。map
提供了双向迭代器来访问其元素;并且在map
中,元素值根据指定的比较函数按键值排序。- 另外,
map
中的元素都具有唯一的键与其对应,每个键都是独一无二的。
3、写在最后
好了,文章的内容就到这里,感谢观看。