• c++ 常用STL 之unordered_map


    c++ 常用STL 之set_kangshuangzhu的博客-CSDN博客 中总结了关联式容器和set。这一篇介绍一下unordered_map的用法。

    之所以介绍unordered_map而不是map,是因为unordered_map在效率上有明显的优势

                      | map             | unordered_map
    ---------------------------------------------------------
    Ordering        | increasing  order   | no ordering
                    | (by default)        |
    
    Implementation  | Self balancing BST  | Hash Table
                    | like Red-Black Tree |  
    
    search time     | log(n)              | O(1) -> Average 
                    |                     | O(n) -> Worst Case
    
    Insertion time  | log(n) + Rebalance  | Same as search
                          
    Deletion time   | log(n) + Rebalance  | Same as search

    unordered_map还是从初始化,增,删,改, 查入手

    初始化

    1. std::unordered_map m1;
    2. // list constructor
    3. std::unordered_map<int, std::string> m2 =
    4. {
    5. {1, "foo"},
    6. {3, "bar"},
    7. {2, "baz"},
    8. };
    9. // copy constructor
    10. std::unordered_map<int, std::string> m3 = m2;
    11. // move constructor
    12. std::unordered_map<int, std::string> m4 = std::move(m2);
    13. // range constructor
    14. std::vectorint>> v = { {"0x12", 1}, {"0x01",-1} };
    15. std::unordered_mapdouble> m5(v.begin(), v.end());

    这里需要注意的问题是unordered_map的key一定得是可hash的,即自己带有hash函数,否则就不能当做unordered_map的key。 不过可以当做map的key,因为map以红黑树形式存储。

    遍历 

    1. std::vectorint>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}};
    2. std::unordered_mapdouble> m5(v.begin(), v.end());
    3. for(auto i: m5){
    4. std::cout << i.first << " " << i.second << std::endl;
    5. }
    6. for(auto i = m5.begin(); i != m5.end(); i++){
    7. std::cout << i -> first << " " << i -> second << std::endl;
    8. }

     在第二种方法中,因为i是迭代器(benzhi jius

    查找某个元素

    1. std::vectorint>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}};
    2. std::unordered_mapdouble> m5(v.begin(), v.end());
    3. auto i = m5.find("0x12");
    4. std::cout << i -> first << " " << i -> second << std::endl;

    如果find没有找到某键值对,则返回迭代其end() 

    这里可以看到查找和遍历的时候,对map的一个键值对的处理特别像pair,事实上c++确实是把map的一个键值对当成了pair来处理的。下面的代码可以很清晰的看到这个特点

    1. std::vector<std::pair<std::string, int>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}};
    2. std::unordered_map<std::string, double> m5(v.begin(), v.end());
    3. auto i = m5.find("0x12");
    4. std::cout << typeid(*i).name() << std::endl;
    5. 输出
    6. NSt3__14pairIKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEdEE

    unordered_map还有一个类似java的写法 map[key]  但是应该特别注意,用这种写法查询一个key的值的时候,如果key不存在,会给把key加入到map中,value添加一个默认值。而且这种写法可以直接修改map中一个key的值

    1. std::unordered_map mp;
    2. std::cout << "kkk " << (mp.find("kkk") == mp.end()) << std::endl;
    3. std::cout << "kkk " << mp["kkk"] << std::endl;
    4. std::cout << "kkk " << (mp.find("kkk") == mp.end()) << std::endl;
    5. mp["kkk"] += "nonono";
    6. std::cout << "kkk " << mp["kkk"] << std::endl;
    7. 输出
    8. kkk 1
    9. kkk
    10. kkk 0
    11. kkk nonono

    value的默认值对数值类型是0 ,string类型是空字符串,其他类型没有尝试过,但为了不增加debug难度,最好不要用于其他的复杂结构。

    有的版本c++中unordered_map有at这个函数,有的版本没有,为了保险起见,最好不要用这个函数。

    判断unordered_map 是否包含某个元素:

    1. umap.find(x) != map.end()//查
    2. //或者
    3. umap.count(x) != 0

    empty()  返回map是否为空

    size()  返回map大小

    unordered_map也是一个无序容器,所以新增元素的时候位置并不重要。

    emplace

    1. std::vectorint>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}};
    2. std::unordered_mapdouble> m5(v.begin(), v.end());
    3. for(auto i: m5){
    4. std::cout << i.first << " " << i.second << std::endl;
    5. }
    6. m5.emplace("kkk",20);
    7. for(auto i = m5.begin(); i != m5.end(); i++){
    8. std::cout << i -> first << " " << i -> second << std::endl;
    9. }

    emplace一次向map中添加一个键值对。

     insert 可以一次性插入多个键值对

    1. std::vectorint>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}};
    2. std::unordered_mapdouble> m5(v.begin(), v.end());
    3. // auto i = m5.find("0x12");
    4. // std::cout << typeid(*i).name() << std::endl;
    5. // std::cout << i -> first << " " << i -> second << std::endl;
    6. for(auto i: m5){
    7. std::cout << i.first << " " << i.second << std::endl;
    8. }
    9. m5.insert({{"kkk",20},{"sss",3}});
    10. for(auto i = m5.begin(); i != m5.end(); i++){
    11. std::cout << i -> first << " " << i -> second << std::endl;
    12. }

    当然,insert也可以用来合并两个map

    1. std::vectorint>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}};
    2. std::unordered_mapdouble> m5(v.begin(), v.end());
    3. for(auto i: m5){
    4. std::cout << i.first << " " << i.second << std::endl;
    5. }
    6. std::unordered_mapdouble> m6 = { {"yyy", 23}, {"uuu", 34}};
    7. m5.insert(m6.begin(), m6.end());
    8. for(auto i = m5.begin(); i != m5.end(); i++){
    9. std::cout << i -> first << " " << i -> second << std::endl;
    10. }

    clear 删除所有元素

    erase 删除某个键值对

    1. std::vectorint>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}};
    2. std::unordered_mapdouble> m5(v.begin(), v.end());
    3. for(auto i: m5){
    4. std::cout << i.first << " " << i.second << std::endl;
    5. }
    6. std::unordered_mapdouble> m6 = { {"yyy", 23}, {"uuu", 34}};
    7. m5.erase("0x03");
    8. for(auto i = m5.begin(); i != m5.end(); i++){
    9. std::cout << i -> first << " " << i -> second << std::endl;
    10. }

    修改一个key的值是用的最多的场景

    1. auto it = umap.find(key) //改
    2. if(it != umap.end()) {it->second = new_value; }

  • 相关阅读:
    Golang 并发机制 CSP模型
    C++ constexpr && consteval && constinit
    Flink集群部署
    再玩玩B端搭建
    SPSS探索性分析
    014 Linux 线上高频使用以及面试高频问题——如何查找大文件并安全的清除?
    38-Jenkins-Publish over SSH插件实现远程部署
    奇葩需求记录 各个系统取数据联表展示
    Pytorch之SwinTransformer图像分类
    通过命令行进行R8混淆
  • 原文地址:https://blog.csdn.net/kangshuangzhu/article/details/127640118