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