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<int, std::string> m2 =
- {
- {1, "foo"},
- {3, "bar"},
- {2, "baz"},
- };
-
- // copy constructor
- std::unordered_map<int, std::string> m3 = m2;
-
- // move constructor
- std::unordered_map<int, std::string> m4 = std::move(m2);
-
- // range constructor
- std::vector
int>> v = { {"0x12", 1}, {"0x01",-1} }; - std::unordered_map
double > m5(v.begin(), v.end());
这里需要注意的问题是unordered_map的key一定得是可hash的,即自己带有hash函数,否则就不能当做unordered_map的key。 不过可以当做map的key,因为map以红黑树形式存储。
遍历
- std::vector
int>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}}; - std::unordered_map
double > 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
int>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}}; - std::unordered_map
double > 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<std::pair<std::string, int>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}};
- std::unordered_map<std::string, double> 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
int>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}}; - std::unordered_map
double > 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
int>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}}; - std::unordered_map
double > 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
int>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}}; - std::unordered_map
double > m5(v.begin(), v.end()); - for(auto i: m5){
- std::cout << i.first << " " << i.second << std::endl;
- }
- std::unordered_map
double> 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
int>> v = { {"0x12", 1}, {"0x01",-1}, {"0x00",-1} ,{"0x03",-2}}; - std::unordered_map
double > m5(v.begin(), v.end()); - for(auto i: m5){
- std::cout << i.first << " " << i.second << std::endl;
- }
- std::unordered_map
double> 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; }