map、multimap和unordered_map(hash_map)以及unorderd_multimap
壹、hash_map & unordered_map
hash_map就是unordered_map中文标准库:unordered_map
搜索、插入和元素移除拥有平均常数时间复杂度。元素在内部不以任何特定顺序排序,而是组织进桶中。元素放进哪个桶完全依赖于其键的哈希。这允许对单独元素的快速访问,因为一旦计算哈希,则它准确指代元素所放进的桶。
multimap 键值可以重复,中文标准库:multimap
贰、std::map
map是一个关联式的容器,它提供一对一(其中第一个可以称为关键字key,每个关键字只能在map中出现一次,且map按照key的大小排序,不是按照插入顺序,第二个称为该关键字的值value)的数据处理能力,它的特点是:增加和删除节点对迭代器的影响很小,除了操作的那个节点,对其他的节点都没有什么影响。map可以修改值value,而不能修改关键字key。
map是容器,pair是容器map的元素,每个pair 可以存储两个值。这两种值的类型没有限制(多个值可以用tuple)
一、构造map,插入map元素
insert和emplace函数返回当前插入元素的迭代器加一个bool值std::pair<std::map<type, type>::iterator, bool>
,insert和emplace插入时不会覆盖原有的键值相同的元素,所以如果插入的元素键值原来已经有了,就会插入失败,返回值的第二个值就为false,相反成功则为true
map插入新的元素,是按照键值排序的,即后插入的元素,键值只要小于前面的元素就会放在前面。
std::map<int, std::string> map1;
map1.insert(std::pair<int, std::string>(1, "abc")); //pair定义在 <utility>
map1.insert(std::map<int, std::string>::value_type(2, "bbb")); //不会覆盖前面的(2,bcd),等于插入失败
map1.insert(std::make_pair(6, "sss"));
map1[0] = "ddd";//这种方式会覆盖前面的元素
std::map<int, std::string> map2{ {1,"abc"},{2,"bcd"},{2,"xyz"} }; //和insert一样,键值相同不会覆盖,即key=2,对应的value是"bcd"
map1.emplace(3, "ggg"); //不会覆盖相同键值的元素
value_type在源码中有如下定义:using value_type = pair<const _Kty, _Ty>;
二、修改map元素
map只能修改值value,不能直接修改键值key,如果要想修改key,可以先把该元素存到一个临时的pair再删除原来map的元素,再修改pair的第一个元素,最后再将修改后的pair插入map
map[key] = value; //直接用数组方式修改,这种方式,如果键值不存在则会插入一个新的元素
std::map<int, std::string>::iterator it = map1.find(2); //搜索键值key,返回一个迭代器,返回end则没找到key
it->second = value; //迭代器方式修改
三、查找、访问map元素
auto z = map1[111]; //返回键为111对应的值,如果键111不存在,则会添加一个值为空键为111的元素
auto y = map1.at(1); // 返回map.second,即返回键值key为1对应的值value,如果键值不匹配则会抛出异常,谨慎使用
auto end = --map.end(); //访问map的最后一个元素,注意--位置
std::map<int, std::string>::iterator it = map1.find(2); //搜索键值key,返回一个迭代器,返回end则没找到key
四、遍历map元素
//1.数组方式遍历(存在局限性,键值要符合条件,比如连续)
std::map<int, int> map3;
for (int i = 0; i < 5; i++)
{
map3.emplace(i, i * 10);
}
for (int i = 0; i < map3.size(); i++)
{
std::cout << i << "," << map3[i] << std::endl;
}
//2.迭代器遍历
for (auto it = map1.begin(); it != map1.end(); it++)
{
std::cout << it->first << "," << it->second << std::endl;
}
//3.反向迭代器遍历
for (auto& x : map1)
{
//x.second = "oooo"; //传引用可以修改值,
std::cout << x.first << "," << x.second << std::endl;
}
rbegin()
和rend()
是反向迭代器,即rbegin() = end()
,rend() = begin()
cbegin、cend,crbegin、crend
都是const型的迭代器,它们不能修改容器的值
const_iterator
对象可以用于const型的容器或非const的容器,它自身的值可以改(可以指向其他元素),但不能改写其指向的元素值
五、删除map元素
- 删除一个节点:
map1.erase(1);
参数为key的值,如果key不存在即删除失败返回0,删除成功返回非0
auto r = map1.erase(iterator)
参数为一个指向map1的迭代器,返回值为删除节点的下一个节点的迭代器,因此参数不能为end()
或rbegin()
,用erase()
清空容器可以这样做:
for(iter=myMap.begin(); iter!=myMap.end(); )
{
iter = myMap.erase(iter);
}
- 清空map:
上面的方式虽然也可以清空容器,不过还有一种更简单的方式:
map1.clear()
示例代码:
点击查看代码
#include <iostream>
#include <map>
#include <utility>
#include <string>
int main()
{
//构造map,插入元素
std::map<int, std::string> map1;
map1.insert(std::pair<int, std::string>(1, "abc")); //pair定义在 <utility>
map1.insert(std::map<int, std::string>::value_type(2, "bcd"));
map1.insert(std::make_pair(6, "sss"));
map1.insert(std::map<int, std::string>::value_type(2, "bbb")); //不会覆盖前面的(2,bcd),等于插入失败
map1[5] = "def";
map1[1] = "aaa";
map1[5] = "ddd";//这种方式会覆盖前面的元素
map1.emplace(3, "ggg");
map1.emplace(3, "sss"); //不会覆盖(3,"ggg")
std::map<int, std::string> map2{ {1,"abc"},{2,"bcd"} ,{5,"def"} ,{2,"xyz"} }; //和insert一样,键值相同不会覆盖,即key=2,对应的value是"bcd"
//map的大小
auto num = map1.size();
//查找map键值并修改值value
std::map<int, std::string>::iterator it = map1.find(2); //搜索键值key,返回一个迭代器,返回end则没找到key
it->second = "fff";
decltype(it) it1 = map1.begin();
auto x = it1->first; // 返回key
auto y = map1.at(1); // 返回map.second,即返回键值为1对应的值 如果键值不匹配则会抛出异常,谨慎使用
auto z = map1[111]; // 返回键为111对应的值,如果键111不存在,则会添加一个值为空,键为111的元素
//遍历元素
//1.数组方式遍历(存在局限性,键值要符合条件,比如连续)
std::map<int, int> map3;
for (int i = 0; i < 5; i++)
{
map3.emplace(i, i * 10);
}
for (int i = 0; i < map3.size(); i++)
{
std::cout << i << "," << map3[i] << std::endl;
}
//2.迭代器遍历
for (auto it = map1.begin(); it != map1.end(); it++)
{
std::cout << it->first << "," << it->second << std::endl;
}
//3.反向迭代器遍历
for (auto& x : map1)
{
//x.second = "oooo"; //传引用可以修改值,
std::cout << x.first << "," << x.second << std::endl;
}
//删除元素
it1 = map1.begin();
auto r0 = map1.erase(it1); //返回值为删除第一个元素后map1的第一个元素
map1.clear(); //清空map1
system("pause");
return 0;
}
map常用操作函数(示例代码出现过的不再描述:
函数 | 作用 |
---|---|
count() | 返回指定元素出现的次数 |
empty() | 如果map为空则返回true |
equal_range() | 返回特殊条目的迭代器对 |
get_allocator() | 返回map的配置器 |
key_comp() | 返回比较元素key的函数 |
lower_bound() | 返回键值 >= 给定元素的第一个位置 |
max_size() | 返回可以容纳的最大元素个数 |
swap() | 交换两个map |
upper_bound() | 返回键值 > 给定元素的第一个位置 |
value_comp() | 返回比较元素value的函数 |