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还是从初始化,增,删,改, 查入手

初始化

    std::unordered_map m1;
 
    // list constructor
    std::unordered_map m2 =
    {
        {1, "foo"},
        {3, "bar"},
        {2, "baz"},
    };
 
    // copy constructor
    std::unordered_map m3 = m2;
 
    // move constructor
    std::unordered_map m4 = std::move(m2);
 
    // range constructor
    std::vector> v = { {"0x12", 1}, {"0x01",-1} };
    std::unordered_map m5(v.begin(), v.end());

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

遍历 

    std::vector> v = { {"0x12", 1}, {"0x01",-1},  {"0x00",-1} ,{"0x03",-2}};
    std::unordered_map m5(v.begin(), v.end());
    for(auto i: m5){
        std::cout << i.first << " " << i.second << std::endl;
    }
    for(auto i = m5.begin(); i != m5.end(); i++){
        std::cout << i -> first << " " << i -> second << std::endl;
    }

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

查找某个元素

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

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

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

    std::vector> v = { {"0x12", 1}, {"0x01",-1},  {"0x00",-1} ,{"0x03",-2}};
    std::unordered_map m5(v.begin(), v.end());
    auto i = m5.find("0x12");
    std::cout << typeid(*i).name()  << std::endl;

输出
NSt3__14pairIKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEdEE

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

    std::unordered_map mp;
    std::cout << "kkk " << (mp.find("kkk") == mp.end()) << std::endl;
    std::cout << "kkk " << mp["kkk"] << std::endl;
    std::cout << "kkk " << (mp.find("kkk") == mp.end()) << std::endl;
    mp["kkk"] += "nonono"; 
    std::cout << "kkk " << mp["kkk"] << std::endl;
输出

kkk 1
kkk 
kkk 0
kkk nonono

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

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

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

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

empty()  返回map是否为空

size()  返回map大小

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

emplace

    std::vector> v = { {"0x12", 1}, {"0x01",-1},  {"0x00",-1} ,{"0x03",-2}};
    std::unordered_map m5(v.begin(), v.end());
    for(auto i: m5){
        std::cout << i.first << " " << i.second << std::endl;
    }
    m5.emplace("kkk",20);
    for(auto i = m5.begin(); i != m5.end(); i++){
        std::cout << i -> first << " " << i -> second << std::endl;
    }

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

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

    std::vector> v = { {"0x12", 1}, {"0x01",-1},  {"0x00",-1} ,{"0x03",-2}};
    std::unordered_map m5(v.begin(), v.end());
    // auto i = m5.find("0x12");
    // std::cout << typeid(*i).name()  << std::endl;
    // std::cout << i -> first << " " << i -> second << std::endl;
    for(auto i: m5){
        std::cout << i.first << " " << i.second << std::endl;
    }
    m5.insert({{"kkk",20},{"sss",3}});
    for(auto i = m5.begin(); i != m5.end(); i++){
        std::cout << i -> first << " " << i -> second << std::endl;
    }

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

    std::vector> v = { {"0x12", 1}, {"0x01",-1},  {"0x00",-1} ,{"0x03",-2}};
    std::unordered_map m5(v.begin(), v.end());
    for(auto i: m5){
        std::cout << i.first << " " << i.second << std::endl;
    }
    std::unordered_map m6 = { {"yyy", 23}, {"uuu", 34}};
    m5.insert(m6.begin(), m6.end());
    for(auto i = m5.begin(); i != m5.end(); i++){
        std::cout << i -> first << " " << i -> second << std::endl;
    }

clear 删除所有元素

erase 删除某个键值对

    std::vector> v = { {"0x12", 1}, {"0x01",-1},  {"0x00",-1} ,{"0x03",-2}};
    std::unordered_map m5(v.begin(), v.end());
    for(auto i: m5){
        std::cout << i.first << " " << i.second << std::endl;
    }
    std::unordered_map m6 = { {"yyy", 23}, {"uuu", 34}};
    m5.erase("0x03");
    for(auto i = m5.begin(); i != m5.end(); i++){
        std::cout << i -> first << " " << i -> second << std::endl;
    }

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

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

你可能感兴趣的:(c++,开发语言)