书接上期我们讲到set容器,这一期我们聊聊同为关联容器的单映射容器map/多映射容器multimap,在实际开发中也经常使用
文章目录
什么是map?
map和multimap区别
map的API
1.map的构造和赋值
2.map交换和大小
3.map的几种初始化
4.map的插入和删除
5.map查找和统计
6.同set一般map的自定义排序(也可以自定义函数写或者仿函数)
map容器的原型,默认的第三个参数其实是less,从小到大
map使用案例:
首先要明白映射类似于函数的对应关系,每个x
对应一个y
,而map
是每个键对应一个值。上期我们讲到pair对组可转入观看,大话STL第五期——set/multiset(含pair对组)
map 容器存储的都是 pair 对象,也就是用 pair 类模板创建的键值对。其中,各个键值对的键和值可以是任意数据类型,pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
- map同set一样所有元素都会根据元素的键值自动排序(默认从小到大)
- 优点:可以根据key值快速找到value值
- 底层数据结构为红黑树
- 另外需要注意的是,使用 map 容器存储的各个键值对,键的值既不能重复也不能被修改
- 同样的与set和multiset类似,map/multimap的唯一区别就是map不允许有重复键值出现,而multimap允许
- map 容器配备的是双向迭代器(bidirectional iterator)。这意味着,map 容器迭代器只能进行 ++p、p++、--p、p--、*p 操作,并且迭代器之间只能使用 == 或者 != 运算符进行比较。
指的是 multimap 容器具有和 map 相同的特性,即 multimap 容器也用于存储 pair
和 map 容器相比,multimap 未提供 at() 成员方法,也没有重载 [] 运算符。这意味着,map 容器中通过指定键获取指定指定键值对的方式,将不再适用于 multimap 容器。其实这很好理解,因为 multimap 容器中指定的键可能对应多个键值对,而不再是 1 个。
map可以
map[xx]++;
map[xx]=xxx..;
multimap不可以这样
int main()
{
mapmp = { {2,10},{1,50},{3,8,} ,{3,15} };//按前后顺序 只能插入到3,8
mp.insert(pair(3, 10)); //插不进去
Show(mp);
multimapmp1 = { {2,10},{1,50},{3,8},{3,11} };//用初始化列表也可以写键值相同的
mp1.insert(pair(3, 10));//可以插进去
Show1(mp1);
return 0;
}
map mp; //map没骗人构造函数
map(const map &mp);//拷贝构造
map& operator=(const map &mp);//重载等号操作符
void Show(map& st)
{
for (auto it = st.begin(); it != st.end(); ++it)
{
cout <<(*it).first<<" "<< it->second<<" " << endl;
}
cout << "------------------" << endl;
}
int main()
{
mapmp;
mp.insert(pair(2, 10));
mp.insert(pair(1, 20));
mp.insert(pair(3, 20));
mp.insert(pair(1, 30));//不允许有重复key值,最后一个pair不会插进去
Show(mp);
//拷贝构造
mapmp1(mp);
Show(mp1);
//赋值
mapmp2;
mp2 = mp1;
Show(mp2);
return 0;
}
size();//返回容器中元素数目
empty();//判断容器是否为空
swap();//交换两个容器
void Show(map& st)
{
for (auto it = st.begin(); it != st.end(); ++it)
{
cout <<(*it).first<<" "<< it->second<<" " << endl;
}
cout << "------------------" << endl;
}
int main()
{
//建议
mapmp = { {2,10},{1,50},{3,8}};//利用初始化列表初始化
Show(mp);
if (mp.empty())
{
cout << "为空" << endl;
}
else
cout << "不空" << endl;
cout << "容器元素个数: " << mp.size() << endl;
//交换
mapmp1{ {1,1},{2,5},{5,10} };
mp.swap(mp1);
Show(mp);
Show(mp1);
return 0;
}
我们可以将它map结点理解为三部分:
理解为四部分,通过键值对进行插入,系统调用对象的运算符[]重载函数,运算符=重载函数实现:
void Show(map& st)
{
for (auto it = st.begin(); it != st.end(); ++it)
{
cout <<(*it).first<<" "<< it->second<<" " << endl;
}
cout << "------------------" << endl;
}
int main()
{
//建议1
mapmp = { {2,10},{1,50},{3,8} };//利用初始化列表初始化
Show(mp);
//2
mapmp1;//直接赋值 map[key]=value;
mp1[2] = 20;
mp1[3] = 50;
mp1[0] = 9;
mp1[int(4)] = 44;
Show(mp1);
//3
mapmp2;//利用insert
mp2.insert({ 1,1 });//建议
mp2.insert(pair(2, 20));
Show(mp2);
return 0;
}
insert(elem);//在元素中插入元素elem
clear();//清楚所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一元素的迭代器
erase(beg,end);//删除区间[beg,end]的所有元素,返回下一个元素的迭代器
erase(key);//删除容器中值为key的元素
int main()
{
mapmp = { {2,10},{1,50},{3,8}};//利用初始化列表初始化
mp.erase(2);//删除key为2的值
Show(mp);
//清空
//mp.erase(mp.begin(), mp.end());
mp.clear();
return 0;
}
find(key);//查找key是否存在,若存在返回该键的迭代器,不存在返回map.end()位置
count(key);//统计,查找键为 key 的键值对的个数并返回。对于map就是0或1
//对于multimap就可能有多个
void Show(map& st)
{
for (auto it = st.begin(); it != st.end(); ++it)
{
cout <<(*it).first<<" "<< it->second<<" " << endl;
}
cout << "------------------" << endl;
}
int main()
{
mapmp = { {2,10},{1,50},{3,8},{1,80} };//利用初始化列表初始化
map::iterator it = mp.find(1);
if (it != mp.end())
{
cout << "找到元素key:" << (*it).first <<" 找到元素:"<second<< endl;
}
else
cout << "没找到元素" << endl;
cout<
sort排序不能针对关联容器(set,map),因为sort会破环关联容器的底层数据结构,详细解释如下。
map中的元素是pair类型对象,每个pair类型由关键字—值(key-value)组成:关键字起到索引的作用,值则表示与索引相关联的数据。字典是一个很好的map例子,可以将单词作为关键字,将单词释义作为值。
map使用的底层数据结构为一颗红黑树(红黑树是一颗高度平衡二叉排序树),因为map的各种操作接口,RB-Tree也都提供了,所以几乎所有的map操作行为,都只是转调用了RB-Tree的操作行为而已。TB-Tree中的key是按弱序排序的,因此map中的key也是按弱序排列的,所以任意更改map的key会严重破坏map组织的,也就是key不能修改(key也就不能使用sort排序。)
C++:map自定义排序
C++ STL中Map的按Key排序和按Value排序_IIcyZhao的博客-CSDN博客_c++ map 按value排序
(map&C++)(五、排序)sort_lzh~的博客-CSDN博客_c++map sort
使用 map 容器存储多个键值对时,该容器会自动根据各键值对的键的大小,按照既定的规则进行排序。默认情况下,map 容器选用std::less
排序规则(其中 T 表示键的数据类型),其会根据键的大小对所有键值对做升序排序。当然,根据实际情况的需要,我们可以手动指定 map 容器的排序规则,既可以选用 STL 标准库中提供的其它排序规则(比如std::greater
),也可以自定义排序规则。
template < class Key, // 指定键(key)的类型
class T, // 指定值(value)的类型
class Compare = less, // 指定排序规则
class Alloc = allocator > // 指定分配器对象的类型
> class map;
class test
{
public:
bool operator()(int v1,int v2)const
{
return v1 > v2;
}
};
bool mm(pair& m, pair& n) 全局才行,放在类里就要加static静态全局
{
return m.second > n.second;
}
// 由于sort不能对map的second直接进行排序,故转化为pair进行排序,单调递减
vector> mmp(mp.begin(), mp.end());
sort(mmp.begin(), mmp.end(), mm);写成函数对象也可以
void Show(map& st)
{
for (auto it = st.begin(); it != st.end(); ++it)
{
cout <<(*it).first<<" "<< it->second<<" " << endl;
}
cout << "------------------" << endl;
}
int main()
{
//从大到小排,与set使用相同
//因为在创建容器时自动排序,因此要在创建的时候更改排序规则
mapmp = { {2,10},{1,50},{3,8},{1,80} };//利用初始化列表初始化
//等同于
//map>mp = { {2,10},{1,50},{3,8},{1,80} };
Show(mp);
return 0;
}
看懂敲一遍最好
#define 策划 0
#define 美术 1
#define 研发 2
class Worker {
public:
string wokername;//员工姓名
int salary;//工资
};
void CreateWorker(vector& ww) {
string name = "ABCDEFGHIJ";
for (int i = 0; i & mm, vector &ww) {
//循环将员工插入容器
for (vector::iterator it = ww.begin(); it != ww.end(); it++) {
int number=rand() % 3;//0 1 2
mm.insert({ number,*it });
}
}
void Show(multimap& mm) {
cout << "策划部门有:" << endl;
multimap::iterator it=mm.find(策划);//找到部门为策划的第一个位置
int index = 0;//设置索引
for (it; it != mm.end() && index < mm.count(策划); index++, it++) {
cout << "姓名:" << it->second.wokername << " 工资:" << it->second.salary << endl;
}
cout << "--------------------------------------------" << endl;
cout << "美术部门有:" << endl;
it = mm.find(美术);//找到部门为策划的第一个位置
index = 0;//设置索引
for (it; it != mm.end() && index < mm.count(美术); index++, it++) {
cout << "姓名:" << it->second.wokername << " 工资:" << it->second.salary << endl;
}
cout << "--------------------------------------------" << endl;
cout << "研发部门有:" << endl;
it = mm.find(研发);//找到部门为策划的第一个位置
index = 0;//设置索引
for (it; it != mm.end() && index < mm.count(研发); index++, it++) {
cout << "姓名:" << it->second.wokername << " 工资:" << it->second.salary << endl;
}
}
int main()
{
srand((unsigned int)time(NULL));//随机数种子
//创建10名员工
vector ww;
CreateWorker(ww);
//将员工分组
multimap mm;
CapWorker(mm,ww);
//分组打印
Show(mm);
return 0;
}
这一期就到此结束了,感谢观看,订阅此专栏。相关代码一定手撸一遍,加深记忆和理解。