一、map容器的特点
1、所有元素都会根据元素的键值自动排序
2、所有的元素都是pair,同时拥有键值和实值。 第一个参数:键值 第二个参数:实值
3、map容器的键值唯一 不可变 实值 可变。
二、map容器的插入、遍历
void test()
{
/*
map/multimap常用API
map构造函数
map<T1, T2> mapTT;//map默认构造函数:
map(const map &mp);//拷贝构造函数
map赋值操作
map& operator=(const map &mp);//重载等号操作符
swap(mp);//交换两个集合容器
map大小操作
size();//返回容器中元素的数目
empty();//判断容器是否为空
map插入数据元素操作
map.insert(...); //往容器插入元素,返回pair<iterator,bool>
map<int, string> mapStu;
//第一种 通过pair的方式插入对象
mapStu.insert(pair<int, string>(3, "小张"));
// 第二种 通过pair的方式插入对象
mapStu.inset(make_pair(‐1, "校长"));
// 第三种 通过value_type的方式插入对象
mapStu.insert(map<int, string>::value_type(1, "小李"));
// 第四种 通过数组的方式插入值
mapStu[3] = "小刘";
mapStu[5] = "小王";
map删除操作
clear();//删除所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg,end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(keyElem);//删除容器中key为keyElem的对组。
map查找操作
find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;/若不存在,返回m
ap.end();
count(keyElem);//返回容器中key为keyElem的对组个数。对map来说,要么是0,要么是
对multimap来说,值可能大于1。
lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。
*/
//存放9527‐‐"星爷" 10086‐"移动" 10010‐‐"联通" 10000‐‐"电信"
//int为键值的类型 string为实值的类型
map<int, string> m;
//第1种:
m.insert(pair<int, string>(9527, "星爷"));
//第2种:(推荐)
m.insert(make_pair(10086, "移动"));
//第3种:
m.insert(map<int, string>::value_type(10010, "联通"));
//第4种:读map容器数据的时候 推荐
m[10000] = "电信";//m.insert(make_pair(10000,"电信"));
//m[10] 寻找key为10的实值
//但是:如果容器中没有key为10 使用m[10] 会创建一个key为10实值为空的 对组
//如果容器中有key为10 那么m[10]代表key=10的实值
//建议:10是存在的
cout << m[10] << endl;
myPrintMap01(m);
#if 0
for_each(m.begin(), m.end(), [](pair<int, string> val) {
cout << "key=" << val.first << ", value=" << val.second << endl;
});
#endif
//只想查看key==9527 的实值 (保证key是存在的)
cout << m[9527] << endl;//"星爷"
cout << m[10010] << endl;//"联通"
//如果不能确定key值是否存在
map<int, string>::const_iterator ret;
ret = m.find(10086);
if (ret == m.end())
{
cout << "未找到相关节点" << endl;
}
else
{
//ret代表的是key=10086的对组的迭代器
cout << "找到相关节点:key=" << (*ret).first << ", value=" << (*ret).second << endl;
}
}
三、multimap案例
公司今天招聘了 5 个员工,5 名员工进入公司之后,需要指派员工在那个部门工作 人员信息有: 姓名 年龄 电话 工资等组成 通过 Multimap 进行信息的插入 保存 显示 分部门显示员工信息 显示全部员工信息
#include<iostream>
#include<map>
#include<algorithm>
#include<time.h>
#include<string>
#include<vector>
using namespace std;
#define SALE_DEPATMENT 1 //销售部门
#define DEVELOP_DEPATMENT 2 //研发部门
#define FINACIAL_DEPATMENT 3 //财务部门
#define ALL_DEPATMENT 4 //所有部门
class Person {
public:
string name;
int age;
double salary;
string tele;
};
//创建五个员工
void createperson(vector<Person> worker)
{
string tmp = "ABCDE";
for (int i = 0; i < tmp.size(); ++i)
{
Person p;
p.name = "员工";
p.name += tmp[i];
p.age = rand() % 30 + 20;
p.salary = rand() % 20000 + 10000;
p.tele = "010-8888888";
worker.push_back(p);
}
}
//5 名员工分配到不同的部门
void Personbygroup(vector<Person> &list, multimap<int, Person> &plist)
{
int operate = -1;//用户的操作
for (vector<Person>::iterator it; it != list.end(); it++)
{
cout << "当前员工信息" << endl;
cout << "姓名:" << it->name << "年龄:" << it->age << "工资"
<< it->salary << "电话" << it->tele << endl;
cout << "请对该员工进行部门分配(1 销售部门, 2 研发部门, 3 财务部门):" << endl;
cin >> operate;
while (true)
{
if (operate == SALE_DEPATMENT) {
plist.insert(make_pair(SALE_DEPATMENT, *it));
break;
}
else if (operate == DEVELOP_DEPATMENT) {
plist.insert(make_pair(DEVELOP_DEPATMENT, *it));
break;
}
else if (operate == FINACIAL_DEPATMENT) {
plist.insert(make_pair(FINACIAL_DEPATMENT, *it));
break;
}
else {
cout << "您的输入有误,请重新输入(1 销售部门, 2 研发部门, 3 财务部门):" << endl;
cin >> operate;
}
}
}
cout << "员工部门分配完毕!" << endl;
cout << "***********************************************************" << endl;
}
//打印员工信息
void Printlist(multimap<int, Person> &mlist , int myoperate)
{
if (myoperate == ALL_DEPATMENT) {
for (multimap<int, Person>::iterator it = mlist.begin(); it != mlist.end(); it++)
{
cout << "姓名:" << it->second.name << " 年龄:" << it->second.age
<< " 工资:" << it->second.salary << " 电话:" << it->second.tele << endl;
}
return;
}
multimap<int, Person>::iterator it = mlist.find(myoperate);
int depatCount = mlist.count(myoperate);
int num = 0;
if (it != mlist.end()) {
while (it != mlist.end() && num < depatCount) {
cout << "姓名:" << it->second.name << " 年龄:" << it->second.age \
<< " 工资:" << it->second.salary << " 电话:" << it->second.tele << endl;
it++;
num++;
}
}
}
//根据用户操作显示不同部门的人员列表
void ShowPersonList(multimap<int, Person>& plist, int myoperate) {
switch (myoperate)
{
case SALE_DEPATMENT:
Printlist(plist, SALE_DEPATMENT);
break;
case DEVELOP_DEPATMENT:
Printlist(plist, DEVELOP_DEPATMENT);
break;
case FINACIAL_DEPATMENT:
Printlist(plist, FINACIAL_DEPATMENT);
break;
case ALL_DEPATMENT:
Printlist(plist, ALL_DEPATMENT);
break;
}
}
//用户操作菜单
void PersonMenue(multimap<int, Person>& plist) {
int flag = -1;
int isexit = 0;
while (true) {
cout << "请输入您的操作((1 销售部门, 2 研发部门, 3 财务部门, 4所有部门, 0 退出):" << endl;
cin >> flag;
switch (flag)
{
case SALE_DEPATMENT:
ShowPersonList(plist, SALE_DEPATMENT);
break;
case DEVELOP_DEPATMENT:
ShowPersonList(plist, DEVELOP_DEPATMENT);
break;
case FINACIAL_DEPATMENT:
ShowPersonList(plist, FINACIAL_DEPATMENT);
break;
case ALL_DEPATMENT:
ShowPersonList(plist, ALL_DEPATMENT);
break;
case 0:
isexit = 1;
break;
default:
cout << "您的输入有误,请重新输入!" << endl;
break;
}
if (isexit == 1) {
break;
}
}
}
int main()
{
vector<Person> vlist; //创建的 5 个员工 未分组
multimap<int, Person> plist; //保存分组后员工信息
//创建 5 个员工
createperson(vlist);
//5 名员工分配到不同的部门
Personbygroup(vlist, plist);
//根据用户输入显示不同部门员工信息列表 或者 显示全部员工的信息列表
PersonMenue(plist);
system("pause");
return 0;
}
四、STL 容器使用时机
vector 的使用场景:比如软件历史操作记录的存储,我们经常要查看历史记录, 比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描 述。
deque 的使用场景:比如排队购票系统,对排队者的存储可以采用 deque, 支持头端的快速移除,尾端的快速添加。如果采用 vector,则头端移除时,会移动 大量的数据,速度慢。
vector 与 deque 的比较: 一:vector.at()比 deque.at() 效率高,比如 vector.at(0)是固定的,deque 的开始位置 却是不固定的。
二:如 果有大量释放操作的话,vector 花的时间更少,这跟二者的内部实现有关。
三: deque 支持头部的快速插入与快速移除,这是 deque 的优点。 list 的使用场景: 比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除 插入。
set 的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高 分到低分的顺序排列。 map 的使用场景:比如按 ID 号存储十万个用户,想要 快速要通过 ID 查找对应的用户。二叉树的查找效率,这时就体现出来了。如果是 vector 容器,最坏的情况下可能要遍历完整个容器才能找到该用户。