map
在STL的头文件中map中定义了模版类map和multimap,用有序二叉树表存储类型为pair<const Key, T>
的元素对序列。序列中的元素以const Key部分作为标识,map中所有元素的Key值必须是唯一的,multimap则允许有重复的Key值。可以将map看作是由Key标识元素的元素集合,这类容器也被称为“关联容器”,可以通过一个Key值来快速决定一个元素,因此非常适合于需要按照Key值查找元素的容器。map容器按照key的大小自动进行排序,默认升序。
定义map对象的代码示例:
map<string, int> m;
在介绍关联容器操作之前,先了解一下pair的标准库类型。pair类型是在有文件utility中定义的,pair是将2个数据组合成一组数据,当需要这样的需求时就可以使用pair,如STL中的map就是将key和value放在一起来保存。另一个应用是,当一个函数需要返回2个数据的时候,可以选择pair。 pair的实现是一个结构体,主要的两个成员变量是first ,second 因为是使用struct不是class,所以可以直接使用pair的成员变量。
pair类型包含了两个数据值,通常有以下的一些定义和初始化的一些方法:
pair<T1, T2> p; //定义了一个空的pair对象p,T1和T2的成员都进行了值初始化 pair<T1, T2> p(v1, v2); // p是一个成员类型为T1和T2的pair; first和second成员分别用v1和v2进行初始化。 make_pair(v1, v2); //以v1和v2值创建的一个新的pair对象
map的基本操作
向map中插入元素
m[key] = value;
m.insert(make_pair(key, value));
[key]操作是map很有特色的操作,如果在map中存在键值为key的元素对, 则返回该元素对的值域部分,否则将会创建一个键值为key的元素对,值域为默认值。所以可以用该操作向map中插入元素对或修改已经存在的元素对的值域部分。
也可以直接调用insert方法插入元素对,insert操作会返回一个pair,当map中没有与key相匹配的键值时,其first是指向插入元素对的迭代器,其second为true;若map中已经存在与key相等的键值时,其first是指向该元素对的迭代器,second为false。
即,insert可能插入失败,用一下代码可以检查是否插入成功:
pair<map<key,value >::iterator, bool> Insert_Pair;
Insert_Pair = m.insert(make_pair(key, value));
if(!Insert_Pair.second)
cout << ""Error insert new element" << endl;
查找元素
m[key];
当与该键值相匹配的元素对存在时,返回对应的值value。要注意的是,当与该键值相匹配的元素对不存在时,会创建键值为key(当另一个元素是整型时,m[key]=0)的元素对。
map<key, value>::iterator it = m.find(key);
如果map中存在与key相匹配的键值时,find操作将返回指向该元素对的迭代器,否则,返回的迭代器等于map的end()(参见vector中提到的begin()和end()操作)。
删除元素
m.erase(key);
删除与指定key键值相匹配的元素对,并返回被删除的元素的个数。
m.erase(it);
有的说m.erase(it)返回指向像一个元素的迭代器,但我的实际操作发现返回的是void,一些博客也提到了这一点。建议是当作返回void使用...
要注意进行安全的删除操作!
错误示范:
{
cout<<iter->first<<":"<<iter->second<<endl;
m.erase(iter);
}
这是一种错误的写法,会导致程序行为不可知.究其原因是map 是关联容器,对于关联容器来说,如果某一个元素已经被删除,那么其对应的迭代器就失效了,不应该再被使用;否则会导致程序无定义的行为。(但是有的博客用这种方法也能得出正确的结果,不过这里提到的无定义行为也有道理,先暂且将这种方法视为错误的方法吧)
正确示范:
for(map<key,value >::iterator iter=m.begin();iter!=m.end();)
{
cout<<iter->first<<":"<<iter->second<<endl;
m.erase(iter++);
}
这种删除方式也是STL源码一书中推荐的方式,分析 m.erase(it++)语句,map中在删除iter的时候,先将iter做缓存,然后执行iter++使之指向下一个结点,再进入erase函数体中执行删除操作,删除时使用的iter就是缓存下来的iter(也就是当前iter(做了加操作之后的iter)所指向结点的上一个结点)。
(m.erase(it++) )和(m.erase(it); iter++; )这个执行序列是不相同的。前者在erase执行前进行了加操作,在it被删除(失效)前进行了加操作,是安全的;后者是在erase执行后才进行加操作,而此时iter已经被删除(当前的迭代器已经失效了),对一个已经失效的迭代器进行加操作,行为是不可预期的,这种写法势必会导致 map操作的失败并引起进程的异常。
其他操作
m.size();
返回元素个数
m.empty();
判断是否为空
m.clear();
清空所有元素
参考链接:
https://blog.csdn.net/forever__1234/article/details/89647975
https://blog.csdn.net/u010029439/article/details/89681773
https://xuanxuanblingbling.github.io/life/study/2019/03/20/STL/
https://www.cnblogs.com/zhoulipeng/p/3432009.html
https://www.cnblogs.com/kex1n/archive/2011/12/06/2278505.html