文章目录
1 map基本概念
map/multimap
属于关联式容器,底层结构采用红黑树实现。
特点:
①map中的所有元素均为对组pair
,即键值对。
②对组pair
中第1个元素为key
(键值),起索引作用;第2个元素为value
(实值)。
③所有元素均按照元素的键值key
自动排序。
优点:
高效,可根据key
值快速查找到对应的value
值。
map和multimap的区别:
map
:不允许容器中存在重复的key
值元素;
multimap
:允许容器中存在重复的key
值元素。
注:实值
value
允许存在重复。
2 map构造函数和赋值【operator=】
作用:创建map容器及赋值。
注1:使用map容器时,需包含头文件
#include <map>
。
注2:map中所有元素均成对出现,插入数据时需使用对组。
构造函数:
①map<T1, T2> mp;
:默认无参构造函数,采用类模板实现。
②map(const map &mp);
:拷贝构造函数,使用已有map对象初始化新的对象。
赋值操作:
map& operator=(const map &mp);
:重载赋值运算符,使用目标map容器,对当前map容器赋值。
示例:map构造函数和赋值
#include <iostream>
using namespace std;
#include <map>
template<typename T1, typename T2>
void printMap(const map<T1, T2>& mp) {
//形参使用const,避免被修改
//形参使用const后,遍历时需使用只读迭代器const_iterator
//使用typename关键字,防止编译器报错:C2760(语法错误,意外标记“标识符”)
for (typename map<T1, T2>::const_iterator it = mp.begin(); it != mp.end(); it++) {
cout << "key = " << (*it).first << " , value = " << it->second << endl;
}
cout << endl;
}
int main() {
//1.默认无参构造
map<int, string> m;
//插入元素,每个元素均为对组
//使用对组pair的匿名对象
m.insert(pair<int, string>(3, "Tom"));
m.insert(pair<int, string>(2, "Jerry"));
m.insert(pair<int, string>(4, "Jack"));
m.insert(make_pair(1, "Lucy"));
printMap<int, string>(m);
//key = 1, value = Lucy
//key = 2, value = Jerry
//key = 3, value = Tom
//key = 4, value = Jack
//2.拷贝构造
map<int, string> m2(m);
printMap<int, string>(m2);
//3.赋值操作
map<int, string> m3;
m3 = m;
printMap<int, string>(m3);
return 0;
}
3 map大小【size()】和交换【swap()】
大小操作:
size();
:获取map容器的大小,即键值对/对组的个数。
empty();
:判断容器是否为空。
交换操作:
swap(mp);
:将目标map容器mp
与自身的元素互换。
示例:
#include <iostream>
using namespace std;
#include <map>
template<typename T1, typename T2>
void printMap(const map<T1, T2>& mp) {
//形参使用const,避免被修改
//形参使用const后,遍历时需使用只读迭代器const_iterator
//使用typename关键字,防止编译器报错:C2760(语法错误,意外标记“标识符”)
for (typename map<T1, T2>::const_iterator it = mp.begin(); it != mp.end(); it++) {
cout << "key = " << (*it).first << " , value = " << it->second << endl;
}
cout << endl;
}
int main() {
map<int, int> m1;
m1.insert(pair<int, int>(1, 10));
m1.insert(pair<int, int>(2, 20));
m1.insert(pair<int, int>(3, 30));
//size():容器大小
cout << "m1的大小:" << m1.size() << endl; //3
//empty():判断是否为空
cout << (m1.empty() ? "空" : "非空") << endl; //非空
cout << "交换前:" << endl;
map<int, int> m2;
m2.insert(pair<int, int>(4, 40));
m2.insert(pair<int, int>(5, 50));
m2.insert(pair<int, int>(6, 60));
printMap<int, int>(m1);
printMap<int, int>(m2);
//swap():容器互换
m1.swap(m2);
cout << "交换后:" << endl;
printMap<int, int>(m1);
printMap<int, int>(m2);
return 0;
}
4 map插入【insert()】和删除【erase()、clear()】
(1)插入元素:使用成员函数insert(..)
向map容器插入元素。
函数原型:
insert(elem);
:向map容器插入键值对/对组元素elem
。
①mp.insert(pair<T1, T2>(v1, v2));
:使用对组的匿名对象。
②mp.insert(make_pair(v1, v2));
:使用make_pair()
函数,无需显式指定数据类型。
③mp.insert(map<T1, T2>::value_type(v1, v2));
:使用map<T1, T2>::value_type()
函数。【不建议】
④mp[key] = val;
:使用重载后的[]
运算符插入元素。【不建议】
注:使用第④种方式插入元素时,若访问不存在的
key
值,则会使用默认值0
自动创建<key, 0>
的对组,不建议用于插入元素,但可用于根据键值key
获取实值。
(2)删除元素:使用成员函数erase(..)
、clear(..)
删除map容器中的元素。
函数原型:
①erase(const_iterator pos);
:删除迭代器指向位置的元素。
②erase(const_iterator start, const_iterator end);
:删除迭代器指向位置[start, end)
区间的所有元素。
③erase(key);
:删除容器中键值为key
的元素。
④clear();
:清空容器中的所有元素。
注:清空容器的所有元素,
mp.clear();
等价于mp.erase(mp.begin(), mp.end());
。
示例:
#include <iostream>
using namespace std;
#include <map>
template<typename T1, typename T2>
void printMap(const map<T1, T2>& mp) {
//形参使用const,避免被修改
//形参使用const后,遍历时需使用只读迭代器const_iterator
//使用typename关键字,防止编译器报错:C2760(语法错误,意外标记“标识符”)
for (typename map<T1, T2>::const_iterator it = mp.begin(); it != mp.end(); it++) {
cout << "key = " << (*it).first << " , value = " << it->second << endl;
}
cout << endl;
}
int main() {
map<int, string> namelist;
/* insert()插入键值对/对组 */
//(1)mp.insert(pair<T1, T2>(v1, v2));:使用对组的匿名对象。
namelist.insert(pair<int, string>(3, "Lucy"));
//(2)mp.insert(make_pair(v1, v2));:使用make_pair()函数,无需显式指定数据类型。
namelist.insert(make_pair(2, "Jerry"));
//(3)mp.insert(map<T1, T2>::value_type(v1, v2));:使用map<T1, T2>::value_type()函数。【不建议】
namelist.insert(map<int, string>::value_type(4, "Tom"));
//(4)mp[key] = val;:使用重载后的[]运算符插入元素。【不建议】
namelist[1] = "Jack";
printMap<int, string>(namelist);
//key = 1, value = Jack
//key = 2, value = Jerry
//key = 3, value = Lucy
//key = 4, value = Tom
/* 删除元素 */
//erase(key)
namelist.erase(4);
printMap<int, string>(namelist);
//key = 1, value = Jack
//key = 2, value = Jerry
//key = 3, value = Lucy
//erase(pos)
namelist.erase(namelist.begin());
printMap<int, string>(namelist);
//key = 2, value = Jerry
//key = 3, value = Lucy
//erase(begin, end)
//clear()
namelist.erase(namelist.begin(), namelist.end());
//namelist.clear();
printMap<int, string>(namelist);
//(空)
return 0;
}
5 map查找【find()】和统计【count()】
查找元素:
find(key);
:查找键值key
是否存在。若存在,则返回该键值对元素的迭代器指向位置;若不存在,则返回结束迭代器 mp.end()。
注:成员函数
find(key);
返回值为迭代器类型。
//判断map容器是否存在某键
int key = 5;
//查找元素,返回迭代器类型
map<int, int>::iterator pos = mp.find(key);
//判断元素是否存在
if (pos != mp.end()) {
cout << "查找到元素key:" << pos->first
<< " ,value = " << (*pos).second << endl;
}
统计元素个数:
count(key);
:统计键值key
的元素个数。
①map容器
:键key
不可重复,返回结果为0
或1
。
②multimap容器
:键key
可重复,返回结果为0
、1
或n
。
示例:map查找元素和统计元素个数
#include <iostream>
using namespace std;
#include <map>
//map容器:key不可重复
void func1() {
map<int, int> mp;
//插入元素
mp.insert(pair<int, int>(2, 20));
mp.insert(pair<int, int>(1, 10));
mp.insert(pair<int, int>(4, 40));
mp.insert(pair<int, int>(3, 30));
//find(key);:查找键值key是否存在。
//若存在,则返回该键值对元素的迭代器指向位置;
//若不存在,则返回结束迭代器 mp.end()。
map<int, int>::iterator pos = mp.find(4);
if (pos != mp.end()) {
cout << "查找到元素key:" << pos->first
<< " ,value = " << (*pos).second << endl;
}
else {
cout << "未查找到元素" << endl;
}
//查找到元素key:4 ,value = 40
//count(key);:统计键值key的元素个数。
cout << mp.count(3) << endl; //1
cout << mp.count(5) << endl; //0
}
//multimap容器:key可重复
void func2() {
multimap<int, int> mmp;
//插入元素
mmp.insert(make_pair(2, 20));
mmp.insert(make_pair(2, 200));
mmp.insert(make_pair(2, 2000));
mmp.insert(pair<int, int>(1, 10));
mmp.insert(pair<int, int>(4, 40));
mmp.insert(pair<int, int>(3, 30));
//find(key);:查找键值key是否存在。
//若存在,则返回该键值对元素的迭代器指向位置;
//若不存在,则返回结束迭代器 mp.end()。
map<int, int>::iterator pos = mmp.find(4);
if (pos != mmp.end()) {
cout << "查找到元素key:" << pos->first
<< " ,value = " << (*pos).second << endl;
}
else {
cout << "未查找到元素" << endl;
}
//查找到元素key:4 ,value = 40
//count(key);:统计键值key的元素个数。
cout << mmp.count(2) << endl; //3
cout << mmp.count(5) << endl; //0
}
int main(){
//func1();
func2();
}
6 map容器排序【仿函数operator()】
map容器默认按键值key
升序排序,利用仿函数,通过重载小括号operator()
在插入元素之前指定排序规则,并在创建map容器对象时,向map容器的类模板参数列表传入指定排序规则。
/* 定义自定义排序规则的仿函数的类 */
//使用类模板增强通用性
template<class T>
class MyCompare {
public:
/* 重载仿函数() */
//第1个小括号:重载小括号运算符
//第2个小括号:operator()函数的形参列表的小括号
//必须使用const修饰operator()函数
//否则编译器报错:const MyCompare的表达式会丢失 const-volatile 限定符
bool operator()(T key1, T key2) const {
return key1 > key2; //降序排序
//return key1 < key2; //升序排序
}
};
/* 创建map容器对象时,向map容器的类模板参数列表传入指定排序规则MyCompare类型 */
//类模板参数列表需传入类型,使用包含仿函数的MyCompare类型
map<double, int, MyCompare<double>> mp;
注:使用map容器对自定义数据类型排序时,必须指定排序规则。
示例:map容器对内置数据类型排序
#include <iostream>
using namespace std;
#include <map>
/* 定义自定义排序规则的仿函数的类 */
//使用类模板增强通用性
template<class T>
class MyCompare {
public:
/* 重载仿函数() */
//第1个小括号:重载小括号运算符
//第2个小括号:operator()函数的形参列表的小括号
//必须使用const修饰operator()函数
//否则编译器报错:const MyCompare的表达式会丢失 const-volatile 限定符
bool operator()(T key1, T key2) const {
return key1 > key2; //降序排序
//return key1 < key2; //升序排序
}
};
int main() {
//创建map容器对象时,向map容器的类模板参数列表传入指定排序规则MyCompare类型
//类模板参数列表需传入类型,使用包含仿函数的MyCompare类型
map<double, int, MyCompare<double>> mp;
//插入元素
mp.insert(pair<double, int>(2.2, 20));
mp.insert(pair<double, int>(3.3, 30));
mp.insert(pair<double, int>(1.1, 10));
mp.insert(pair<double, int>(4.4, 40));
for (map<double, int, MyCompare<double>>::iterator it = mp.begin(); it != mp.end(); it++) {
cout << "key = " << (*it).first << " , value = " << it->second << endl;
}
//key = 4.4, value = 40
//key = 3.3, value = 30
//key = 2.2, value = 20
//key = 1.1, value = 10
return 0;
}
7 案例练习:员工分组
案例描述:
10名员工(ABCDEFGHIJ)分配不同部门:
①员工信息:姓名、工资;部门:共3个部门。
②随机为10名员工分配部门和工资。
③通过multimap插入键值对信息<部门编号, 员工对象>。
④分部门显示员工信息。
思路:
①vector容器存放员工对象。
②遍历vector容器,对员工随机分组。
③分组后,将键值对信息<部门编号, 员工对象>存放至multimap容器。
④分部门显示员工信息。
案例代码:
#include <iostream>
using namespace std;
#include <vector>
#include <map>
#include <ctime>
#define CPP 1
#define JAVA 2
#define PYTHON 3
//员工类
class Employee {
public:
string name;
int salary;
};
//添加员工信息
void addEmployee(vector<Employee>& v) {
string nameSeed = "ABCDEFGHIJ";
for (int i = 0; i < 10; i++) {
Employee emp;
emp.name = "员工";
emp.name += nameSeed[i];
//工资赋随机值
emp.salary = rand() % 10001 + 10000; //10000~20000
//将员工对象插入至vector容器
v.push_back(emp);
}
}
//分配员工部门
void setDepartment(vector<Employee> &v, multimap<int, Employee> &mp) {
//遍历vector容器,将员工对象插入至map中
for (vector<Employee>::iterator it = v.begin(); it != v.end(); it++) {
//部门编号赋随机值
int deptId = rand() % 3 + 1; //1~3
mp.insert(make_pair(deptId, *it));
}
}
//分部门显示员工信息
void showEmpInfo(multimap<int, Employee>& mp) {
cout << "C++开发部门:" << endl;
//查询在容器中的起始位置
multimap<int, Employee>::iterator pos = mp.find(CPP);
//统计部门人数
int count = mp.count(CPP);
//遍历某个部门的全部员工
int index = 0;
for (; pos != mp.end() && index < count; pos++, index++) {
cout << "员工姓名:" << pos->second.name
<< ",工资:" << pos->second.salary << endl;
}
cout << "----------------------------" << endl;
cout << "Java开发部门:" << endl;
//查询在容器中的起始位置
pos = mp.find(JAVA);
//统计部门人数
count = mp.count(JAVA);
//遍历某个部门的全部员工
index = 0;
for (; pos != mp.end() && index < count; pos++, index++) {
cout << "员工姓名:" << pos->second.name
<< ",工资:" << pos->second.salary << endl;
}
cout << "----------------------------" << endl;
cout << "Python开发部门:" << endl;
//查询在容器中的起始位置
pos = mp.find(PYTHON);
//统计部门人数
count = mp.count(PYTHON);
//遍历某个部门的全部员工
index = 0;
for (; pos != mp.end() && index < count; pos++, index++) {
cout << "员工姓名:" << pos->second.name
<< ",工资:" << pos->second.salary << endl;
}
}
int main() {
//添加随机化种子
srand((unsigned int)time(NULL));
//1.添加员工信息
vector<Employee> vec;
addEmployee(vec);
//2.员工分组
multimap<int, Employee> mp;
setDepartment(vec, mp);
//3.分部门显示员工信息
showEmpInfo(mp);
return 0;
}