map 的基本概念
map是c++标准库中定义的关联容器,用于存储关键字(key)-值(value)形式的键值对。key 和 value可以是任意你需要的类型。
map 中的键 key不能重复,可以作为索引来快速定位对应的值。如果插入一个键值对时,key 已经在容器中存在,会导致新的值覆盖原先的值。(multimap 允许容器中有重复key值元素。)
map內部的实现自建一颗红黑树,这颗树具有对数据自动排序的功能,在map内部所有的数据都是有序的。
构造函数与赋值操作
功能描述:
- 对map容器进行构造和赋值操作
构造函数:
map<T1, T2> mp;
//map默认构造函数:map(const map &mp);
//拷贝构造函数
赋值操作:
map& operator=(const map &mp);
//重载等号操作符
#include<iostream>
#include<string>
#include<map>
using namespace std;
/*打印输出map*/
void print_map(map<string,int>& m) {
for (map<string, int>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "key = " << it->first << " value = " << it->second << endl;
}
cout << endl;
}
int main() {
// 默认构造函数
map<string, int> m1;
/*插入键值对*/
m1.insert(pair<string, int>("张三", 18));
m1.insert(make_pair("李四",20));
m1.insert(make_pair("王五",12));
m1.insert(make_pair("老六",3));
print_map(m1);
/* 默认按照 key 升序排序
key = 老六 value = 3
key = 李四 value = 20
key = 王五 value = 12
key = 张三 value = 18
*/
/*拷贝构造函数*/
map<string, int> m2(m1);
print_map(m2);
/*
key = 老六 value = 3
key = 李四 value = 20
key = 王五 value = 12
key = 张三 value = 18
*/
m2.insert(pair<string, int>("老王", 38));
/*赋值操作*/
map<string, int>m3 = m2;
print_map(m3);
/*
key = 老六 value = 3
key = 老王 value = 38
key = 李四 value = 20
key = 王五 value = 12
key = 张三 value = 18
*/
return 0;
}
map 容器大小与容器交换
功能描述:
- 统计map容器大小以及交换map容器
函数原型:
size();
//返回容器中元素的数目empty();
//判断容器是否为空swap(st);
//交换两个集合容器
#include<iostream>
#include<string>
#include<map>
using namespace std;
/*打印输出map*/
void print_map(map<string,int>& m) {
for (map<string, int>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "key = " << it->first << " value = " << it->second << endl;
}
cout << endl;
}
/*大小、和交换*/
void test43_2() {
map<string, int> m;
m.insert(make_pair<string,int>("张三", 25));
m.insert(pair<string, int>("老王", 44));
m.insert(make_pair<string, int>("老六", 33));
cout << "m:" << endl;
print_map(m);
/*
key = 老六 value = 33
key = 老王 value = 44
key = 张三 value = 25
*/
/*判断m容器是否为空*/
if (m.empty()) {
cout << "m为空" << endl;
}
else {
cout << "m的大小为:" << m.size() << endl;//m的大小为:3
}
/*交换 m 与 m2 容器中的数据*/
map<int, int>m2;
m2.insert(pair<int, int>(1, 100));
m2.insert(pair<int, int>(2, 200));
m2.insert(pair<int, int>(3, 300));
m2.insert(pair<int, int>(4, 400));
// 类型不同无法交换
// m.swap(m1);
/*交换 m 与 m3 容器中的数据*/
map<string, int>m3;
m3.insert(make_pair<string, int>("小明", 3));
m3.insert(pair<string, int>("小红", 2));
m3.insert(make_pair<string, int>("小花", 5));
m3.insert(make_pair<string, int>("小胖", 7));
cout << "m3:" << endl;
print_map(m3);
/*
key = 小红 value = 2
key = 小花 value = 5
key = 小明 value = 3
key = 小胖 value = 7
*/
m.swap(m3);
cout << "m:" << endl;
print_map(m);
/*
key = 小红 value = 2
key = 小花 value = 5
key = 小明 value = 3
key = 小胖 value = 7
*/
cout << "m3:" << endl;
print_map(m3);
/*
key = 老六 value = 33
key = 老王 value = 44
key = 张三 value = 25
*/
}
int main() {
test43_2();
return 0;
}
插入与删除
功能描述:
- map容器进行插入数据和删除数据
函数原型:
insert(elem);
//在容器中插入元素。clear();
//清除所有元素erase(pos);
//删除pos迭代器所指的元素,返回下一个元素的迭代器。erase(beg, end);
//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。erase(key);
//删除容器中值为key的元素。
#include<iostream>
#include<string>
#include<map>
using namespace std;
void test51_1() {
map<string, int>m;
/*insert函数插入键值对 返回 pair 组对,第一个值指向为插入成功的元素的迭代器,第二个值为是否插入成功*/
m.insert(pair<string,int>("关羽",4));
// 插入成功的元素是:key = 张飞,value = 2
pair<map<string, int>::iterator, bool> r1 = m.insert(pair<string, int>("张飞", 2));
if (r1.second) {
cout << "插入成功的元素是:key = " << r1.first->first << ",value = " << r1.first->second << endl;
}
else {
cout << "插入失败" << endl;
}
// 插入失败
pair<map<string, int>::iterator, bool> r2 = m.insert(pair<string, int>("关羽", 4));
if (r2.second) {
cout << "插入成功的元素是:key = " << r2.first->first << ",value = " << r2.first->second << endl;
}
else {
cout << "插入失败" << endl;
}
m.insert(pair<string,int>("赵云",1));
m.insert(pair<string,int>("刘备",7));
/*使用迭代器遍历*/
for (map<string, int>::iterator p = m.begin(); p != m.end(); p++) {
cout << "键:" << p->first << ",值:" << p->second << endl;
}
/*
键:关羽,值:4
键:刘备,值:7
键:张飞,值:2
键:赵云,值:1
*/
/*迭代器 指向第一个元素*/
map<string, int>::iterator p = m.begin();
/*获取迭代器指向的元素*/
cout << "键:" << p->first << ",值:" << p->second << endl; // 键:关羽,值:4
/*删除迭代器指向的元素 返回指向下一个元素的迭代器*/
map<string, int>::iterator p_next = m.erase(p);
cout << "键:" << p_next->first << ",值:" << p_next->second << endl; // 键:刘备,值:7
for (map<string, int>::iterator p = m.begin(); p != m.end(); p++) {
cout << "键:" << p->first << ",值:" << p->second << endl;
}
/*
键:刘备,值:7
键:张飞,值:2
键:赵云,值:1
*/
cout << "------------------------------------" << endl;
map<string, int>::iterator p_first = m.begin(); // 指向第一个元素的迭代器
p_first++; // 向后移动一个位置
map<string, int>::iterator p_end = m.end(); // 指向最后一个元素的迭代器
/*删除迭代器指向区间内的元素 :第二个到最后一个之间的元素*/
m.erase(p_first,p_end);
for (map<string, int>::iterator p = m.begin(); p != m.end(); p++) {
cout << "键:" << p->first << ",值:" << p->second << endl;
}
/*
键:刘备,值:7
*/
/*清空map容器*/
m.clear();
cout << m.size() << endl; // 0
/*根据键删除元素*/
m.insert(pair<string,int>("曹操",99));
cout << m.size() << endl; // 1
m.erase("曹操");
cout << m.size() << endl; // 0
}
int main() {
test51_1();
return 0;
}
元素查找与统计
功能描述:
- 对map容器进行查找数据以及统计数据
函数原型:
find(key);
查找key是否存在,若存在,返回该键的元素的迭代器(如果是multimap,存在重复的Key时,返回第一个);若不存在,返回set.end();count(key);
//统计key的元素个数(对于map,由于key不能重复,所以只会返回0或1)
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main() {
map<string, int>m;
m.insert(make_pair<string,int>("C",1));
m.insert(make_pair<string,int>("C++",2));
m.insert(make_pair<string,int>("C++",3));
m.insert(make_pair<string,int>("Java",3));
m.insert(make_pair<string,int>("Python",4));
m.insert(make_pair<string,int>("C#",5));
/*统计指定key的个数*/
cout << m.count("C++") << endl;; // 1
cout << m.count("JS") << endl; // 0
/*根据key查找元素,如果找到,返回指向该元素的迭代器,
如果没有找到,返回指向map容器最后一个元素的下一个位置的迭代器*/
// key = C++,value = 2
map<string, int>::iterator p1 = m.find("C++");
if (p1 != m.end()) {
cout << "key = " << p1->first << ",value = " << p1->second<<endl;
}
else {
cout << "未找到元素" << endl;
}
// 未找到元素
map<string, int>::iterator p2 = m.find("JS");
if (p2 != m.end()) {
cout << "key = " << p2->first << ",value = " << p2->second<<endl;
}
else {
cout << "未找到元素" << endl;
}
multimap<string, int>m2;
m2.insert(make_pair<string, int>("C", 1));
m2.insert(make_pair<string, int>("C++", 2));
m2.insert(make_pair<string, int>("C++", 3));
m2.insert(make_pair<string, int>("Java", 3));
m2.insert(make_pair<string, int>("Python", 4));
m2.insert(make_pair<string, int>("C#", 5));
// 如果找到多个,返回第一个匹配的元素
map<string, int>::iterator p3 = m2.find("C++");
// key = C++,value = 2
if (p3 != m2.end()) {
cout << "key = " << p3->first << ",value = " << p3->second << endl;
}
else {
cout << "未找到元素" << endl;
}
p3++; // 迭代器往后移动一个位置
cout << "key = " << p3->first << ",value = " << p3->second << endl; // key = C++,value = 3
cout << m2.count("C++") << endl;; // 2
cout << m2.count("JS") << endl; // 0
return 0;
}
map 容器排序规则
map容器默认排序规则为 按照key值进行 从小到大排序。
利用仿函数,可以改变排序规则。
例如,key 是 int 类型,需要按照值从大到小降序排序
#include<iostream>
#include<string>
#include<map>
using namespace std;
class MapCompare {
public:
// 需要加 const
// 否则报错:error C3848: 具有类型“const MapCompare”的表达式会丢失一些 const-volatile 限定符以调用“bool MapCompare::operator ()(int,int)”
bool operator()(int a, int b) const{
return a > b;
}
};
int main() {
/*key 为 int 默认从小到大排序*/
/*在构建容器时,传入指定的比较规则*/
map<int, string, MapCompare>m;
m.insert(pair<int, string>(1, "C++"));
m.insert(pair<int, string>(2, "C"));
m.insert(pair<int, string>(3, "Java"));
m.insert(pair<int, string>(4, "Python"));
for (map<int, string>::iterator p = m.begin(); p != m.end(); p++) {
cout << "key = " << p->first << ",value = " << p->second << endl;
}
/*
key = 4,value = Python
key = 3,value = Java
key = 2,value = C
key = 1,value = C++
*/
return 0;
}
map 使用案例:员工分组统计
案例描述
- 公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在那个部门工作
- 员工信息有: 姓名 工资组成;部门分为:策划、美术、研发
- 随机给10名员工分配部门和工资
- 通过multimap进行信息的插入 key(部门编号) value(员工)
- 分部门显示员工信息
实现步骤
- 创建10名员工,放到vector中
- 遍历vector容器,取出每个员工,进行随机分组
- 分组后,将员工部门编号作为key,具体员工作为value,放入到multimap容器中
- 分部门显示员工信息
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
const string NAMES = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
class Employee {
public:
string name;
int age;
int dept_id;
Employee(string name, int age, int dept_id) {
this->name = name;
this->age = age;
this->dept_id = dept_id;
}
};
/*重载左移操作符*/
ostream& operator<<(ostream& out, const Employee& e) {
out << "部门ID:" << e.dept_id << ",姓名:" << e.name << ",年龄:" << e.age;
return out;
}
/*Employee对象按照年龄降序排序*/
bool EmployeeCompare(Employee& e1, Employee& e2) {
return e1.age > e2.age;
}
// 输出Employee对象
void print_emp(const Employee& e) {
cout << e << endl;
}
/*创建26个员工存入vector容器*/
void create_employee(vector<Employee>& v) {
string s = "Emp-";
for (int i = 0; i < 26; i++) {
// 姓名
string name = s + NAMES[i];
// 年龄 18 -35
int age = (rand() % (35 - 18 + 1)) + 18;
// 部门ID 95-99
int dept_id = (rand() % (99 - 95 + 1)) + 95;
// 存入vector
Employee e(name,age,dept_id);
v.push_back(e);
}
// 按照年龄降序排序
sort(v.begin(),v.end(), EmployeeCompare);
// 使用算法遍历 vector
cout << "============员工数据生成================" << endl;
for_each(v.begin(),v.end(), print_emp);
}
/*将员工按照部门di分组存入multimap*/
void group(const vector<Employee>& v, multimap<int, Employee>& m) {
for (int i = 0; i < v.size(); i++) {
m.insert(pair<int, Employee>(v[i].dept_id, v[i]));
}
}
/*根据部门ID展示员工信息*/
void show_emp_bydept(const multimap<int, Employee>& m) {
cout << "============根据部门统计员工信息================" << endl;
// 部门ID 为 95-99,作为循环条件
for (int n = 95; n <= 99; n++) {
// 获取当前部门ID = n 的员工数量
int coutn_deptid = m.count(n);
cout << "部门ID为 " << n << " 的员工有:" << coutn_deptid << "个" << endl;
// 获取指向部门ID = n 的第一个员工的迭代器
multimap<int, Employee>::const_iterator p = m.find(n);
// 如果找到,就循环,
if (p != m.end()) {
// 循环次数就是 当前 key 出现的次数
for (int i = 0; i < coutn_deptid; i++) {
cout << "部门ID = " << p->first << ",员工信息 = " << p->second << endl;
// 迭代器指向下一个位置
p++;
}
}
// 统计完成一个部门的信息
cout << "============================================" << endl;
}
}
int main() {
// 随机种子
srand((unsigned int) time(NULL));
// 存储employee的容器
vector<Employee> v;
// 存储以按照部门编号分组的员工
multimap<int, Employee> m;
// 装入员工
create_employee(v);
// 员工分组
group(v, m);
// 根据部门ID统计各自数量,部门id区间 [95,99]
show_emp_bydept(m);
}
============员工数据生成================
部门ID:96,姓名:Emp-D,年龄:35
部门ID:95,姓名:Emp-I,年龄:35
部门ID:99,姓名:Emp-T,年龄:34
部门ID:95,姓名:Emp-B,年龄:33
部门ID:96,姓名:Emp-C,年龄:33
部门ID:99,姓名:Emp-Q,年龄:32
部门ID:95,姓名:Emp-H,年龄:30
部门ID:97,姓名:Emp-G,年龄:29
部门ID:96,姓名:Emp-S,年龄:28
部门ID:99,姓名:Emp-Z,年龄:28
部门ID:98,姓名:Emp-A,年龄:27
部门ID:99,姓名:Emp-R,年龄:27
部门ID:99,姓名:Emp-Y,年龄:27
部门ID:99,姓名:Emp-E,年龄:26
部门ID:98,姓名:Emp-M,年龄:26
部门ID:99,姓名:Emp-O,年龄:25
部门ID:97,姓名:Emp-V,年龄:25
部门ID:97,姓名:Emp-J,年龄:24
部门ID:96,姓名:Emp-X,年龄:22
部门ID:98,姓名:Emp-L,年龄:20
部门ID:99,姓名:Emp-F,年龄:19
部门ID:96,姓名:Emp-K,年龄:19
部门ID:96,姓名:Emp-N,年龄:19
部门ID:96,姓名:Emp-P,年龄:19
部门ID:97,姓名:Emp-W,年龄:19
部门ID:99,姓名:Emp-U,年龄:18
============根据部门统计员工信息================
部门ID为 95 的员工有:3个
部门ID = 95,员工信息 = 部门ID:95,姓名:Emp-I,年龄:35
部门ID = 95,员工信息 = 部门ID:95,姓名:Emp-B,年龄:33
部门ID = 95,员工信息 = 部门ID:95,姓名:Emp-H,年龄:30
============================================
部门ID为 96 的员工有:7个
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-D,年龄:35
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-C,年龄:33
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-S,年龄:28
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-X,年龄:22
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-K,年龄:19
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-N,年龄:19
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-P,年龄:19
============================================
部门ID为 97 的员工有:4个
部门ID = 97,员工信息 = 部门ID:97,姓名:Emp-G,年龄:29
部门ID = 97,员工信息 = 部门ID:97,姓名:Emp-V,年龄:25
部门ID = 97,员工信息 = 部门ID:97,姓名:Emp-J,年龄:24
部门ID = 97,员工信息 = 部门ID:97,姓名:Emp-W,年龄:19
============================================
部门ID为 98 的员工有:3个
部门ID = 98,员工信息 = 部门ID:98,姓名:Emp-A,年龄:27
部门ID = 98,员工信息 = 部门ID:98,姓名:Emp-M,年龄:26
部门ID = 98,员工信息 = 部门ID:98,姓名:Emp-L,年龄:20
============================================
部门ID为 99 的员工有:9个
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-T,年龄:34
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-Q,年龄:32
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-Z,年龄:28
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-R,年龄:27
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-Y,年龄:27
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-E,年龄:26
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-O,年龄:25
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-F,年龄:19
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-U,年龄:18
============================================
C:\Users\86182\Desktop\C++\Stage05-STL\x64\Debug\Stage05-STL.exe (进程 6376)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .