map中插入元素的方法有如下集中
map<int, string> mymap;
mymap[1] = "a";
map的源码中重载了[]操作符,
map<_Key, _Tp, _Compare, _Allocator>::operator[](key_type&& __k)
{
return __tree_.__emplace_unique_key_args(__k,
_VSTD::piecewise_construct,
_VSTD::forward_as_tuple(_VSTD::move(__k)),
_VSTD::forward_as_tuple()).first->__get_value().second;
}
而且从上面代码不难看出,[]操作,先是move掉了map中原有的数据,再将新数据放进去,所以用[]操作的话,可以改变map中已有的key对应的value。
make_pair是比较方便的方法,该方法可以根据传入的两个参数,直接构造成一个pari对象,insert到map中。
mymap.insert(make_pair(3, "c"));
可以使用pari方法插入kv对。
mymap.insert(pair<int, string>(4, "d"));
为了避免隐式转换,可以使用value_type来传递类型,value_type是容器中本身提供的型别定义。
mymap.insert(map<int, string>::value_type(2, "b"));
需要注意的一点是,所有insert方式,如果插入的key值在map中原来存在,都不能改变其原来对应的值。
bool one_in_map = mymap.find(1) != mymap.end()? true:false;
如果key在map中,find方法会返回key对应的迭代器。如果key不存在,find会返回end。
bool five_in_map = mymap.count(5) > 0? true: false;
count方法可以统计key在map中出现的次数。对于map来书,key不能重复,因此count方法返回值为1或者0。
前面我们已经提到了find方法可以找到key对应的迭代器
string one_value = mymap.find(1)->second;
at方法可以直接返回key对应的值
string two_value = mymap.at(2);
[]也可以直接获取key对应的值。不过需要注意的是,如果key不在map中,[]这种方式会将key插入map中,而前面的find方法,at方法, 都会报异常。
string six_value = mymap[6];
erase方法可以删除map中的元素。
mymap.erase(1);
注意删除元素的时候,当删除迭代器所指向的对象时,迭代器可能会失效。
for(iter=mymap.begin(); iter!=mymap.end(); iter++) {
mymap.erase(iter);
}
上述代码在运行的时候就会报错,在我自己机器上测试的时候会有如下错误
libc++abi.dylib: terminating with uncaught exception of type std::bad_alloc: std::bad_alloc
对iter直线的元素进行erase时,会使得iter不再成为一个有效的迭代器,如果此后未对iter重新设值就使用iter,会出现异常。iter++就能导致一个未定义行为。
如果我们要在迭代器中删除元素,可以按照如下方式:
for(iter=mymap.begin(); iter!=mymap.end();) {
if (iter->second=="c") {
mymap.erase(iter++);
} else {
iter++;
}
}
遍历容器是最常见的需求,一般可以通过下面两种方式来遍历。
map<int, string>::iterator iter;
for(iter=mymap.begin(); iter!=mymap.end(); iter++) {
cout<<iter->first<<": "<<iter->second<<endl;
}
上面的iter类型比较复杂,我们可以偷懒使用auto关键字,让编译器自动推断类型。
for(auto node: mymap) {
cout<<node.first<<": "<<node.second<<endl;
}
unordered_map与map的用法基本一直,最大的区别在于:
map的key是有序的,而unordered_map的key为无序。
void f2() {
map<int, string> commap;
unordered_map<int, string> umap;
commap[1]="a"; commap[3]="c"; commap[2]="b"; commap[4]="d";
umap[1]="aa"; umap[3]="cc"; umap[4]="dd"; umap[2]="bb";
for(auto node: commap) {
cout<<node.first<<": "<<node.second<<endl;
}
for(auto node: umap) {
cout<<node.first<<": "<<node.second<<endl;
}
}
以上代码输出:
2: b
3: c
4: d
2: bb
4: dd
3: cc
1: aa
对比map与unordered_map,两者的区别如下:
实现方式:unordered_map为哈希表,map为红黑树。
查找操作:unordered_map 平均为O(1),最差为O(n), map为log(n)。
插入,删除操作:unordered_map与查找一样,map为log(n)+平衡二叉树所用的时间。
适用场景:unordered_map适用查找频率高,而map适合要求key有序的场景。
void f2() {
map<int, string> commap;
unordered_map<int, string> umap;
commap[1]="a"; commap[3]="c"; commap[2]="b"; commap[4]="d";
umap[1]="aa"; umap[3]="cc"; umap[4]="dd"; umap[2]="bb";
for(auto node: commap) {
cout<<node.first<<": "<<node.second<<endl;
}
for(auto node: umap) {
cout<<node.first<<": "<<node.second<<endl;
}
}
输出结果为
1: a
2: b
3: c
4: d
2: bb
4: dd
3: cc
1: aa
map的key,默认是按照升序排列的,可以参考一下其中源码
template <class _Key, class _Tp, class _Compare = less<_Key>,
class _Allocator = allocator<pair<const _Key, _Tp> > >
class _LIBCPP_TEMPLATE_VIS map
...
其中less的签名为
struct _LIBCPP_TEMPLATE_VIS less : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x < __y;}
};
根据上述代码不难看出,less是一个结构体,重载了()操作符,是一个函数对象,默认升序排列。
如果我们想让map按key降序排列,可以这样
map<string, int, greater<string>> map1;
其中greater与less就是对应的,表示降序。
如果想自定义排序规则,也是可以的。
void f3() {
map<string, int, greater<string>> map1;
map1["a"]=1; map1["b"]=2; map1["c"]=3; map1["d"]=4;
for(auto node: map1) {
cout<<node.first<<": "<<node.second<<endl;
}
cout<<endl;
map<string, int, myCompare> map2;
map2["bbbb"]=1; map2["ccc"]=2; map2["a"]=3; map2["dd"]=4;
for(auto node: map2) {
cout<<node.first<<": "<<node.second<<endl;
}
}
int main(int argc, char const *argv[])
{
f3();
return 0;
}
d: 4
c: 3
b: 2
a: 1
bbbb: 1
ccc: 2
dd: 4
a: 3
我们重写了一个类似less结构体,重载()操作符,就可以实现自己的排序规则。
如果我们想要对map按照value排序,可以利用stl库中的sort方法。我们可以将map中的元素先拷贝到vector中,再对vector进行排序。
bool mycompare_func(const pair<string, int> &a, const pair<string, int> &b) {
if (a.second==b.second) return a.first>b.first;
else return a.second>b.second;
}
void f4() {
map<std::string, int> mymap{{"b", 1}, {"d", 2}, {"c", 3}, {"a", 4}};
vector<pair<std::string, int>> v(mymap.begin(), mymap.end());
sort(v.begin(), v.end(), mycompare_func);
for(auto node: v) {
cout<<node.first<<": "<<node.second<<endl;
}
}
int main(int argc, char const *argv[])
{
f4();
return 0;
}
最后代码输出结果为
a: 4
c: 3
d: 2
b: 1