C++ STL(九):map/multimap容器


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不可重复,返回结果为01
multimap容器:键key可重复,返回结果为01n

示例: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;
}

猜你喜欢

转载自blog.csdn.net/newson92/article/details/113931051