c++ map unordered_map使用大全

Posted bitcarmanlee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++ map unordered_map使用大全相关的知识,希望对你有一定的参考价值。

1.插入元素

map中插入元素的方法有如下集中

1.1 直接用[]符

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。

1.2 make_pair

make_pair是比较方便的方法,该方法可以根据传入的两个参数,直接构造成一个pari对象,insert到map中。

mymap.insert(make_pair(3, "c"));

1.3 pair

可以使用pari方法插入kv对。

mymap.insert(pair<int, string>(4, "d"));

1.4 value_type

为了避免隐式转换,可以使用value_type来传递类型,value_type是容器中本身提供的型别定义。

mymap.insert(map<int, string>::value_type(2, "b"));

需要注意的一点是,所有insert方式,如果插入的key值在map中原来存在,都不能改变其原来对应的值。

2.判断元素是否存在

2.1 find方法

bool one_in_map = mymap.find(1) != mymap.end()? true:false;

如果key在map中,find方法会返回key对应的迭代器。如果key不存在,find会返回end。

2.2 count方法

bool five_in_map = mymap.count(5) > 0? true: false;

count方法可以统计key在map中出现的次数。对于map来书,key不能重复,因此count方法返回值为1或者0。

3.获取key对应的值

3.1 find方法

前面我们已经提到了find方法可以找到key对应的迭代器

string one_value = mymap.find(1)->second;

3.2 at方法

at方法可以直接返回key对应的值

string two_value = mymap.at(2);

3.3 []操作符

[]也可以直接获取key对应的值。不过需要注意的是,如果key不在map中,[]这种方式会将key插入map中,而前面的find方法,at方法, 都会报异常。

string six_value = mymap[6];

4.删除元素

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++;
        
    

5.遍历map

遍历容器是最常见的需求,一般可以通过下面两种方式来遍历。

5.1 通过迭代器

    map<int, string>::iterator iter;

    for(iter=mymap.begin(); iter!=mymap.end(); iter++) 
        cout<<iter->first<<": "<<iter->second<<endl;
    

5.2 auto关键字

上面的iter类型比较复杂,我们可以偷懒使用auto关键字,让编译器自动推断类型。

    for(auto node: mymap) 
        cout<<node.first<<": "<<node.second<<endl;
    

6.unordered_map用法

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

7.map自定义key排序规则

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结构体,重载()操作符,就可以实现自己的排序规则。

8.map按value排序

如果我们想要对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

以上是关于c++ map unordered_map使用大全的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ unordered_map 中有效地使用 [] 运算符

C++ std::unordered_map 中使用的默认哈希函数是啥?

C++ unordered_map使用自定义类型作为键值

c++ 中的 map 和 unordered_map 在内存使用方面有啥区别吗?

使用自定义类类型作为键的 C++ unordered_map

使用自定义类类型作为键的 C++ unordered_map