头文件:
#include<map>
- map的特性是,所有元素都会根据元素的键值自动排序。
- map所有的元素都是pair,同时拥有实值和键值,pair的第一元素被视为键值,第二元素被视为实值,map不允许两个元素有相同的键值。
- 可以根据key值快速找到value值
- 我们不可以通过map的迭代器改变map的键值, 因为map的键值关系到map元素的排列规则,任意改变map键值将会严重破坏map组织。如果想要修改元素的实值,那么是可以的。
- map和list拥有相同的某些性质,当对它的容器元素进行新增操作或者删除操作时,操作之前的所有迭代器,在操作完成之后依然有效,当然被删除的那个元素的迭代器必然是个例外。
- map 容器配备的是双向迭代器(bidirectional iterator)。这意味着,map 容器迭代器只能进行 ++p、p++、–p、p–、*p 操作,并且迭代器之间只能使用 == 或者 != 运算符进行比较。
- map支持下标访问符,即在[]中放入key,就可以找到与key对应的value的引用。其实在map中,中括号已经被重载为有不存在即插入的功能(对于自定义类型会调用值的默认构造函数,对于int类型则为0)。于是如果查找的key不存在,则map中会增加很多垃圾数据
- multimap和map的操作类似,唯一区别multimap键值可重复。
- map和multimap都是以红黑树为底层实现机制。
map原型
std::map
template <class Key,
class T,
class Compare = less<Key>,
class Alloc = allocator<pair<const Key, T> >
> class map;
key:键值对中的key的类型
T:键值中value的类型
Compare:比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)
该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标注库提供的空间配置器
map容器的构造与赋值
函数 | 描述 |
---|---|
map<T,T> m | map默认构造函数 |
map(const map &mp) | 拷贝构造函数 |
map& operator=(const map &mp) | 重载等号操作符 |
实例:
#include<iostream>
#include<map>
using namespace std;
//map容器的构造与赋值
void printMap(map<int,int> &m) {
for (auto it = m.begin(); it != m.end(); it++) {
cout << "key =" << it->first << " value =" << it->second << endl;
}
cout << endl;
}
int main() {
//创建map容器
map<int, int> m;
//插入数据里面需要传入的是对组
m.insert(pair<int, int>(1, 10));//pair<int, int>(1, 10)为匿名二元组
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(4, 40));
m.insert(pair<int, int>(2, 20));
//插入元素后会根据key自动进行升序排列
printMap(m);
//拷贝构造
map<int, int> m2(m);
printMap(m2);
//赋值
map<int, int> m3;
m3 = m2;
printMap(m3);
return 0;
}
map容器中所有的元素都是成对出现的,插入数据的时候要使用二元组,即对组pair。
map容器的大小与交换
函数 | 描述 |
---|---|
size() | 返回容器中元素的数目 |
empty() | 判断容器中是否为空 |
swap(st) | 交换两个集合容器 |
实例:
#include<iostream>
#include<map>
using namespace std;
//map容器的大小与交换
void printMap(map<int,int> &m) {
for (auto it = m.begin(); it != m.end(); it++) {
cout << "key值为:" << it->first << " value值为:" << it->second << endl;
}
cout << endl;
}
int main() {
map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(2, 20));
if (m.empty()) {
cout << "m容器为空" << endl;
}
else {
cout << "m容器不为空" << endl;
cout << "m的大小为:" << m.size() << endl;
}
//交换
map<int, int> m2;
m2.insert(pair<int,int>(4, 40));
m2.insert(pair<int,int>(6, 60));
m2.insert(pair<int,int>(5, 50));
cout << "map容器交换前" << endl;
printMap(m);
printMap(m2);
cout << "map容器交换后" << endl;
m.swap(m2);
printMap(m);
printMap(m2);
return 0;
}
map容器的插入与删除
函数 | 描述 |
---|---|
insert(elem) | 在容器中插入元素 |
pair<iterator,bool> insert(const value_type &x) | 在map中插入键值对x,iterator代表插入元素的位置,bool代表是否插入成功 |
iterator insert(iterator position, const value_type &x | 在position位置插入值为x的键值对,返回该键值对在map中的位置,注意:元素不一定必须插入在position位置,该位置指示一个参考 |
template void insert(InputIterator first, InputIterator last) | 在map中插入first到last区间中的元素 |
clear() | 清除所有元素 |
erase(pos) | 删除pos迭代器所指的元素,返回下一个元素的迭代器 |
erase(beg,end) | 删除区间[beg,end)的所有元素,返回下一个元素的迭代器 |
erase(key) | 删除容器中值为key的元素 |
map插入数据的三种方法:
- 通过 insert 函数插入 pair
- 通过insert 函数插入 value_type(其实value_type就是pair的typedef)
- 用数组方式插入数据
区别:以上三种用法,虽然都可以实现数据的插入,但是它们是有区别的。第一种和第二种在效果上是完成一样的,用 insert 函数插入数据,在数据的插入上涉及到集合的唯一性这个概念,即当 map 中已经存在某个关键字时,insert 操作是不能成功插入数据,但是用数组方式则可以,它可以覆盖以前该关键字对应的值。
实例:
#include<iostream>
#include <map>
using namespace std;
//map容器的插入与删除操作
void printMap(map<int,int> &m) {
for (auto it = m.begin(); it != m.end(); it++) {
cout << "key值为:" << it->first << " value值为:" << it->second << endl;
}
cout << endl;
}
int main() {
map<int, int> m;
//插入 第一种
m.insert(pair<int, int>(1, 10));
//插入 第二种
m.insert(make_pair(2, 20));
//插入 第三种 不建议使用
m.insert(map<int, int>::value_type(3, 30));
//插入 第四种 最简单
//[]不建议插入 通过[]可以利用key访问到value
//使用[]插入元素的时候,如果key不存在将会自动创建键值对
m[4] = 40;
printMap(m);
//删除
m.erase(m.begin());
printMap(m);
//删除 直接传入key
m.erase(3);
printMap(m);
//全部删除
m.clear();//相当于m.erase(m.begin(),m.end())
printMap(m);
return 0;
}
map容器的查找与统计
函数 | 描述 |
---|---|
find(key) | 查找key是否存在,返回该键的元素的迭代器;若不存在返回map.end() |
mapped_type& at (const key_type& k) | 返回键值k对应value的引用,如果k不在map中,那么out_of_range exception异常抛出(C++11新特性) |
mapped_type& operator[] (const key_type& k) | 返回key对应的value,可以通过返回查看当前元素是否在map中 |
count(key) | 统计key的元素的个数 |
注意:multimap不支持[]操作符
实例1:
#include<iostream>
#include<map>
using namespace std;
int main() {
//查找
map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(2, 20));
//查找键为3的键值对
map<int,int>::iterator pos=m.find(3);
if (pos != m.end()) {
cout << "查到了元素 key=" << pos->first << " value=" << pos->second << endl;
}
else {
cout << "未找到元素" << endl;
}
//统计
//由于map容器中key不能重复出现 因此count统计的结果只有0或1
int num=m.count(3);//返回结果为整型
cout << "num=" << num << endl;
return 0;
}
注意:find返回的是迭代器,而count返回的是整型;而map 中的key是唯一的,因此该函数的返回值要么为0,要么为1,因此可以用该函数来检测一个key是否在map中
实例2:
#include<iostream>
#include<map>
using namespace std;
int main()
{
map<string,string> m;
// 向map中插入元素的方式
// 将键值对<"peach", "桃子">插入到Map,用pair直接来构造键值对
m.insert(pair<string, string>("peach", "桃子"));
//将键值对<"watermel", "西瓜">插入到map中,用make_pair函数来构造键值对
m.insert(make_pair("watermel", "西瓜"));
// 先拿到该容器中的键值对类型,然后插入
m.insert(map<string,string>::value_type("peach", "桃子"));
// key不存在时抛异常
//m.at("banan") = "香蕉";
// 这个的原理是,先用key和T()构造一个键值对,然后调用insert函数将该键值对插入到map中
// 如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器,
// 如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器,
// operator[]函数最后将insert的返回值中的value返回
m["banan"] = "香蕉";
// 输出Map的大小
cout << m.size() << endl;
// 用迭代器去遍历map中的元素,可以得到一个按照key排序的序列
for(auto &e : m)
{
cout << e.first << "--->" << e.second << endl;
}
cout << endl;
// map中的键值对key一定是唯一的,如果key存在将插入失败
auto ret = m.insert(make_pair("peach", "桃色"));
if(ret.second)
{
cout << "<peach, 桃色>不在map中,已经插入" << endl;
}
else
{
cout << "键值为peach已经在map:" << ret.first->first << ":" << ret.first->second << endl;
}
// 删除key为apple的元素
m.erase("apple");
for(auto&e : m)
{
cout << e.first << "--->" << e.second << endl;
}
if(1 == m.count("apple"))
{
cout << "apple还在" << endl;
}
else
{
cout << "apple被吃了" << endl;
}
return 0;
}
map比较
比较两个关键字在map中位置的先后
key_compare key_comp() const;
实例:
#include<iostream>
#include<map>
using namespace std;
int main(){
map<char,int> mymap;
map<char,int>::key_compare mycomp = mymap.key_comp();
mymap['a']=100;
mymap['b']=200;
bool b=mycomp('a', 'b'); // a排在b前面,因此返回结果为true
cout<<b<<endl;
return 0;
}
map自定义排序规则
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排序。)
使用 map 容器存储多个键值对时,该容器会自动根据各键值对的键的大小,按照既定的规则进行排序。默认情况下,map 容器选用std::less< T >排序规则(其中 T 表示键的数据类型),其会根据键的大小对所有键值对做升序排序。当然,根据实际情况的需要,我们可以手动指定 map 容器的排序规则,既可以选用 STL 标准库中提供的其它排序规则(比如std::greater< T >),也可以自定义排序规则。
template < class Key, // 指定键(key)的类型
class T, // 指定值(value)的类型
class Compare = less<Key>, // 指定排序规则
class Alloc = allocator<pair<const Key,T> > // 指定分配器对象的类型
> class map;
实例:
#include<iostream>
#include<map>
using namespace std;
class myCompare
{
public:
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
int main()
{
map<int, int, myCompare> m;
m.insert(pair<int, int>(1,10));
m.insert(make_pair(2,20));
m.insert(map<int,int>::value_type(3,30));
m[4] = 40;
for(map<int, int, myCompare>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "key :" << it->first << "value :" << it->second << endl;
}
return 0;
}
map迭代器
共有八个获取迭代器的函数:begin, end, rbegin, rend 以及对应的 cbegin, cend, crbegin, crend。
二者的区别在于:后者一定返回 const_iterator,而前者则根据map的类型返回iterator 或者 const_iterator。const情况下,不允许对值进行修改。如下面代码所示:
map<int,int>::iterator it;
map<int,int> mmap;
const map<int,int> const_mmap;
it = mmap.begin(); //iterator
mmap.cbegin(); //const_iterator
const_mmap.begin(); //const_iterator
const_mmap.cbegin(); //const_iterator
返回的迭代器可以进行加减操作,此外,如果map为空,则 begin = end
multimap
multimap 容器具有和 map 相同的特性,即 multimap 容器也用于存储 pair<const K, T> 类型的键值对(其中 K 表示键的类型,T 表示值的类型),其中各个键值对的键的值不能做修改;并且,该容器也会自行根据键的大小对存储的所有键值对做排序操作。和 map 容器的区别在于,multimap 容器中可以同时存储多(≥2)个键相同的键值对。
和 map 容器相比,multimap 未提供 at() 成员方法,也没有重载 [] 运算符。这意味着,map 容器中通过指定键获取指定指定键值对的方式,将不再适用于 multimap 容器。其实这很好理解,因为 multimap 容器中指定的键可能对应多个键值对,而不再是 1 个。
map可以
map[xx]++;
map[xx]=xxx..;
multimap不可以这样
实例1:
#include<iostream>
#include<map>
using namespace std;
void Show(map<int,int> &m){
for(map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "key :" << it->first << " value :" << it->second << endl;
}
cout<<endl;
}
void Show_M(multimap<int,int> &m){
for(multimap<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "key :" << it->first << " value :" << it->second << endl;
}
cout<<endl;
}
int main()
{
map<int, int>mp = { {2,10},{1,50},{3,8,} ,{3,15} };//按前后顺序 只能插入到3,8
mp.insert(pair<int, int>(3, 10)); //插不进去
Show(mp);
multimap<int, int>mp1 = { {2,10},{1,50},{3,8},{3,11} };//用初始化列表也可以写键值相同的
mp1.insert(pair<int, int>(3, 10));//可以插进去
Show_M(mp1);
return 0;
}
实例2:
#include<iostream>
#include<map>
using namespace std;
void test1()
{
multimap<string, string> m;
m.insert(make_pair("李逵", "黑旋风"));
m.insert(make_pair("林冲", "豹子头"));
m.insert(make_pair("鲁达", "花和尚"));
m.insert(make_pair("李逵", "铁牛"));
cout << m.size() << endl;
for(auto& e : m)
{
cout << "<" << e.first << "," << e.second << ">" << endl;
}
cout << m.count("李逵") << endl;
cout<<endl;
}
void test2()
{
multimap<int, int> m;
for(int i = 0; i < 10; ++i)
{
m.insert(pair<int,int>(i, i));
}
for(auto& e : m)
{
cout << e.first << "--->" << e.second << endl;
}
cout << endl;
auto it = m.lower_bound(5);
cout << it->first << "--->" << it->second << endl;
cout << endl;
it = m.upper_bound(5);
cout << it->first << "--->" << it->second << endl;
}
int main(){
test1();
test2();
return 0;
}
参考博文:
https://blog.csdn.net/soinlove36/article/details/119796794
https://blog.csdn.net/qq_51447436/article/details/126711431
https://blog.csdn.net/weixin_43718250/article/details/100751494
https://blog.csdn.net/lemonxiaoxiao/article/details/121204095
https://blog.csdn.net/weixin_51609435/article/details/126392880