unordered_map 容器和 map 容器仅有一点不同,即 map 容器中存储的数据是有序的,而 unordered_map 容器中是无序的。
unordered_map 容器和 map 容器仅有一点不同,即 map 容器中存储的数据是有序的,而unordered_map 容器中是无序的。
template < class Key, // 键值对中键的类型
class T, // 键值对中值的类型
class Hash = hash<Key>, //容器内部存储键值对所用的哈希函数
class Pred = equal_to<Key>, // 判断各个键值对键相同的规则
class Alloc = allocator< pair<const Key,T> > // 指定分配器对象的类型
> class unordered_map;
参数 | 含义 |
---|---|
前 2 个参数分别用于确定键值对中键和值的类型,也就是存储键值对的类型。 | |
Hash = hash | 用于指明容器在存储各个键值对时要使用的哈希函数,默认使用 STL 标准库提供的 hash 哈希函数。注 意,默认哈希函数只适用于基本数据类型(包括 string 类型),而不适用于自定义的结构体或者类。 |
Pred = equal_to unordered_map | 容器中存储的键不能相等,判断是否相等的规则,就由此参数指定。默认情况下,使用 STL 标准库中提供的 equal_to 规则,该规则仅支持可直接用 == 运算符做比较的数据类型。 |
默认构造函数
std::unordered_map<std::string, std::string> umap;
创建的同时初始化
std::unordered_map<std::string, std::string> umap{
{"Python 教程","http://c.biancheng.net/python/"},
{"Java 教程","http://c.biancheng.net/java/"},
{"Linux 教程","http://c.biancheng.net/linux/"} };
拷贝/移动构造函数
// 拷贝构造函数
std::unordered_map<std::string, std::string> umap2(umap);
// 移动构造函数
// 返回临时 unordered_map 容器的函数
std::unordered_map <std::string, std::string > retUmap(){
std::unordered_map<std::string, std::string>tempUmap{
{"Python 教程","http://c.biancheng.net/python/"},
{"Java 教程","http://c.biancheng.net/java/"},
{"Linux 教程","http://c.biancheng.net/linux/"} };
return tempUmap;
}
// 调用移动构造函数,创建 umap2 容器
std::unordered_map<std::string, std::string> umap2(retUmap());
选择已有容器部分区域创建
//传入 2 个迭代器,
std::unordered_map<std::string, std::string> umap2(++umap.begin(),umap.end());
成员方法 | 功能 |
---|---|
begin() | 返回指向容器中第一个键值对的正向迭代器。 |
end() | 返回指向容器中最后一个键值对之后位置的正向迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。 |
empty() | 若容器为空,则返回 true;否则 false。 |
size() | 返回当前容器中存有键值对的个数。 |
max_size() | 返回容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同。 |
operator[key] | 该模板类中重载了 [] 运算符,其功能是可以向访问数组中元素那样,只要给定某个键值对的键 key,就可以获取该键对应的值。注意,如果当前容器中没有以 key 为键的键值对,则其会使用该键向当前容器中插入一个新键值对。 |
at(key) | 返回容器中存储的键 key 对应的值,如果 key 不存在,则会抛出 out_of_range 异常。 |
find(key) | 查找以 key 为键的键值对,如果找到,则返回一个指向该键值对的正向迭代器;反之,则返回一个指向容器中最后一个键值对之后位置的迭代器(如果 end() 方法返回的迭代器)。 |
count(key) | 在容器中查找以 key 键的键值对的个数。 |
equal_range(key) | 返回一个 pair 对象,其包含 2 个迭代器,用于表明当前容器中键为 key 的键值对所在的范围。 |
emplace() | 向容器中添加新键值对,效率比 insert() 方法高。 |
emplace_hint() | 向容器中添加新键值对,效率比 insert() 方法高。 |
insert() | 向容器中添加新键值对。 |
erase() | 删除指定键值对。 |
clear() | 清空容器,即删除容器中存储的所有键值对。 |
swap() | 交换 2 个 unordered_map 容器存储的键值对,前提是必须保证这 2 个容器的类型完全相等。 |
bucket_count() | 返回当前容器底层存储键值对时,使用桶(一个线性链表代表一个桶)的数量。 |
max_bucket_count() | 返回当前系统中,unordered_map 容器底层最多可以使用多少桶。 |
bucket_size(n) | 返回第 n 个桶中存储键值对的数量。 |
bucket(key) | 返回以 key 为键的键值对所在桶的编号。 |
load_factor() | 返回 unordered_map 容器中当前的负载因子。负载因子,指的是的当前容器中存储键值对的数量(size())和使用桶数(bucket_count())的比值,即 load_factor() = size() / bucket_count()。 |
max_load_factor() | 返回或者设置当前 unordered_map 容器的负载因子。 |
rehash(n) | 将当前容器底层使用桶的数量设置为 n。 |
reserve() | 将存储桶的数量(也就是 bucket_count() 方法的返回值)设置为至少容纳 count 个元(不超过最大负载因子)所需的数量,并重新整理容器。 |
hash_function() | 返回当前容器使用的哈希函数对象。 |
对于实现互换 2 个相同类型 unordered_map 容器的键值对,除了可以调用该容器模板类中提供的
swap() 成员方法外,STL 标准库还提供了同名的 swap() 非成员函数。
C++ STL 标准库中,不仅是 unordered_map 容器,所有无序容器的底层实现都采用的是哈希表存储结构。更准确地说,是用“链地址法”(又称“开链法”)解决数据存储位置发生冲突的哈希表。
当使用无序容器存储键值对时,会先申请一整块连续的存储空间,但此空间并不用来直接存储键值对,而是存储各个链表的头指针,各键值对真正的存储位置是各个链表的节点。 STL 标准库通常选用 vector 容器存储各个链表的头指针。
当有新键值对存储到无序容器中时,整个存储过程分为好几步:
将该键值对中键的值带入设计好的哈希函数,会得到一个哈希值(一个整数,用 H 表示);
将 H 和无序容器拥有桶的数量 n 做整除运算(即 H % n),该结果即表示应将此键值对存储到的桶的编号;
建立一个新节点存储此键值对,同时将该节点链接到相应编号的桶上。 哈希表存储结构有一个重要的属性,称为负载因子(load factor)。该属性同样适用于无序容器,用于衡量容器存储键值对的空/满程序,即负载因子越大,意味着容器越满,即各链表中挂载着越多的键值对,这无疑会降低容器查找目标键值对的效率;反之,负载因子越小,容器肯定越空,但并不一定各个链表中挂载的键值对就越少。
无序容器中,负载因子的计算方法为: 负载因子 = 容器存储的总键值对 / 桶数
默认情况下,无序容器的最大负载因子为 1.0。如果操作无序容器过程中,使得最大复杂因子超过了默认值,则容器会自动增加桶数,并重新进行哈希,以此来减小负载因子的值。需要注意的是,此过程会导致容器迭代器失效,但指向单个键值对的引用或者指针仍然有效。
无序容器管理哈希表的成员方法
成员方法 | 功能 |
---|---|
bucket_count() | 返回当前容器底层存储键值对时,使用桶的数量。 |
max_bucket_count() | 返回当前系统中,unordered_map 容器底层最多可以使用多少个桶。 |
bucket_size(n) | 返回第 n 个桶中存储键值对的数量。 |
bucket(key) | 返回以 key 为键的键值对所在桶的编号。 |
load_factor() | 返回 unordered_map 容器中当前的负载因子。 |
max_load_factor() | 返回或者设置当前 unordered_map 容器的最大负载因子。 |
rehash(n) | 尝试重新调整桶的数量为等于或大于 n 的值。如果 n 大于当前容器使用的桶数,则该方法会是容器重新哈希, 该容器新的桶数将等于或大于 n。反之,如果 n 的值小于当前容器使用的桶数,则调用此方法可能没有任何作用。 |
reserve(n) | 将容器使用的桶数(bucket_count() 方法的返回值)设置为最适合存储 n 个元素的桶数。 |
hash_function() | 返回当前容器使用的哈希函数对象。 |
成员方法 | 功能 |
---|---|
begin() | 返回指向容器中第一个键值对的正向迭代器。 |
end() | 返回指向容器中最后一个键值对之后位置的正向迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。 |
find(key) | 查找以 key 为键的键值对,如果找到,则返回一个指向该键值对的正向迭代器;反之,则返回一个指向容器中最后 一个键值对之后位置的迭代器(如果 end() 方法返回的迭代器)。 |
equal_range(key) | 返回一个 pair 对象,其包含 2 个迭代器,用于表明当前容器中键为 key 的键值对所在的范围。 |
equal_range(key) | 很少用,因为该容器中存储的键值都不相等 |
利用下标访问普通数组中元素,如果没有则添加
// 创建 umap 容器
unordered_map<string, string> umap{
{"Python 教程","http://c.biancheng.net/python/"},
{"Java 教程","http://c.biancheng.net/java/"},
{"Linux 教程","http://c.biancheng.net/linux/"} };
// 获取 "Java 教程" 对应的值
string str = umap["Java 教程"];
// 添加
umap["C 教程"] = "http://c.biancheng.net/c/";
at() 成员方法,查找失败会报错
//创建 umap 容器
unordered_map<string, string> umap{
{"Python 教程","http://c.biancheng.net/python/"},
{"Java 教程","http://c.biancheng.net/java/"},
{"Linux 教程","http://c.biancheng.net/linux/"} };
//获取指定键对应的值
string str = umap.at("Python 教程");
find() 成员方法。成功返回指向该键值对的迭代器,失败返回 end() 方法一致的迭代器,指向最后一个键值对之后位置。
unordered_map<string, string> umap{
{"Python 教程","http://c.biancheng.net/python/"},
{"Java 教程","http://c.biancheng.net/java/"},
{"Linux 教程","http://c.biancheng.net/linux/"} };
unordered_map<string, string>::iterator iter = umap.find("Python 教程");
unordered_map<string, string>::iterator iter2 = umap.find("GO 教程"); // 查找失败
if (iter2 == umap.end())
cout << "当前容器中没有以\"GO 教程\"为键的键值对";
通过 begin()/end() 或者 cbegin()/cend() 遍历
insert() 方法可以向已建 unordered_map 容器中添加新的键值对。根据功能的不同,共有四种用法。
将 pair 类型键值对添加到容器中
// 以普通方式传递参数
pair<iterator,bool> insert ( const value_type& val );
// 以右值引用的方式传递参数
template <class P>
pair<iterator,bool> insert ( P&& val );
返回 pair 类型值,内部包含一个 iterator 迭代器和 bool 变量,添加成功 bool 为 True,添加失败 bool 为 False。
// 创建空 umap 容器
unordered_map<string, string> umap;
// 构建要添加的键值对
std::pair<string, string>mypair("STL 教程", "http://c.biancheng.net/stl/");
// 创建接收 insert() 方法返回值的 pair 类型变量
std::pair<unordered_map<string, string>::iterator, bool> ret;
// 调用 insert() 方法的第一种语法格式
ret = umap.insert(mypair);
// 调用 insert() 方法的第二种语法格式
ret = umap.insert(std::make_pair("Python 教程","http://c.biancheng.net/python/"));
指定新键值对要添加到容器中的位置
// 以普通方式传递 val 参数
iterator insert ( const_iterator hint, const value_type& val );
// 以右值引用方法传递 val 参数
template <class P>
iterator insert ( const_iterator hint, P&& val );
hint 参数为迭代器,用于指定新键值对要添加到容器中的位置;val 参数指的是要添加容器中的键值对;添加成功返回的迭代器指向新添加的键值对,失败返回的迭代器指向容器中已有相同的键值对。注意最终存储的位置实际上不取决于 hint 参数(hash)
// 创建空 umap 容器
unordered_map<string, string> umap;
// 构建要添加的键值对
std::pair<string, string>mypair("STL 教程", "http://c.biancheng.net/stl/");
// 创建接收 insert() 方法返回值的迭代器类型变量
unordered_map<string, string>::iterator iter;
// 调用第一种语法格式
iter = umap.insert(umap.begin(), mypair);
// 调用第二种语法格式
iter = umap.insert(umap.begin(),std::make_pair("Python 教程", "http://c.biancheng.net/python/"));
将某个 unordered_map 容器指定区域所有键值对复制到另一个 unordered_map 容器中
template <class InputIterator>
void insert ( InputIterator first, InputIterator last );
其中 first 和 last 都为迭代器,[first, last)表示复制其它 unordered_map 容器中键值对的区域。
// 创建并初始化 umap 容器
unordered_map<string, string> umap{
{"STL 教程","http://c.biancheng.net/stl/"},
{"Python 教程","http://c.biancheng.net/python/"},
{"Java 教程","http://c.biancheng.net/java/"} };
// 创建一个空的 unordered_map 容器
unordered_map<string, string> otherumap;
// 指定要拷贝 umap 容器中键值对的范围
unordered_map<string, string>::iterator first = ++umap.begin();
unordered_map<string, string>::iterator last = umap.end();
// 将指定 umap 容器中 [first,last) 区域内的键值对复制给 otherumap 容器
otherumap.insert(first, last);
一次想 unordered_map 容器添加多个键值对
void insert(initializer_list<value_type> il);
il 参数指可用于初始化列表的形式指定多个键值对元素
// 创建空的 umap 容器
unordered_map<string, string> umap;
umap.insert({ {"STL 教程","http://c.biancheng.net/stl/"},
{"Python 教程","http://c.biancheng.net/python/"},
{"Java 教程","http://c.biancheng.net/java/"} });
template <class... Args>
pair<iterator, bool> emplace ( Args&&... args );
参数 args 表示可直接向该方法传递创建新键值对所需要的 2 个元素的值,其中第一个元素将作为键值对的键,另一个作为键值对的值。
当 emplace() 成功添加新键值对时,返回的迭代器指向新添加的键值对,bool 值为 True; 当 emplace()
添加新键值对失败时,说明容器中本就包含一个键相等的键值对,此时返回的迭代器指向的就是容器中键相同的这个键值对,bool 值为 False。
// 创建 umap 容器
unordered_map<string, string> umap;
// 定义一个接受 emplace() 方法的 pair 类型变量
pair<unordered_map<string, string>::iterator, bool> ret;
// 调用 emplace() 方法
ret = umap.emplace("STL 教程", "http://c.biancheng.net/stl/");
emplace_hint() 方法的语法格式如下:
template <class... Args>
iterator emplace_hint ( const_iterator position, Args&&... args );
emplace_hint 不同之处:
emplace_hint() 方法的返回值仅是一个迭代器,而不再是 pair 类型变量。当该方法将新键值对成功添加到容器中时,返回的迭代器指向新添加的键值对;反之,如果添加失败,该迭代器指向的是容器中和要添加键值对键相同的那个键值对。 emplace_hint()方法还需要传递一个迭代器作为第一个参数,该迭代器表明将新键值对添加到容器中的位置。需要注意的是,新键值对添加到容器中的位置,并不是此迭代器说了算,最终仍取决于该键值对的键的值。该迭代器仅是建议。
// 创建 umap 容器
unordered_map<string, string> umap;
// 定义一个接受 emplace_hint() 方法的迭代器
unordered_map<string,string>::iterator iter;
// 调用 empalce_hint() 方法
iter = umap.emplace_hint(umap.begin(),"STL 教程", "http://c.biancheng.net/stl/");
erase():删除 unordered_map 容器中指定的键值对;
clear():删除 unordered_map 容器中所有的键值对,即清空容器。
接受一个正向迭代器,并删除该迭代器指向的键值对
// 创建 umap 容器
unordered_map<string, string> umap{
{"STL 教程", "http://c.biancheng.net/stl/"},
{"Python 教程", "http://c.biancheng.net/python/"},
{"Java 教程", "http://c.biancheng.net/java/"} };
// 定义一个接收 erase() 方法的迭代器
unordered_map<string,string>::iterator ret;
// 删除容器中第一个键值对
ret = umap.erase(umap.begin());
返回一个指向被删除键值对之后位置的迭代器。
根据键值对的键来删除键值对
size_type erase ( const key_type& k );
k 表示目标键值对的键的值;返回一个整数,表示成功删除的键值对的数量
// 创建 umap 容器
unordered_map<string, string> umap{
{"STL 教程", "http://c.biancheng.net/stl/"},
{"Python 教程", "http://c.biancheng.net/python/"},
{"Java 教程", "http://c.biancheng.net/java/"} };
int delNum = umap.erase("Python 教程"); // delNum 为 1
删除指定范围内的所有键值对
unordered_map<string, string> umap{
{"STL 教程", "http://c.biancheng.net/stl/"},
{"Python 教程", "http://c.biancheng.net/python/"},
{"Java 教程", "http://c.biancheng.net/java/"} };
unordered_map<string, string>::iterator first = umap.begin();
unordered_map<string, string>::iterator last = --umap.end();
// 删除[fist,last)范围内的键值对
auto ret = umap.erase(first, last); // 将仅剩最后一个键值对
一次性删除 unordered_map 容器中所有键值对
unordered_map<string, string> umap{
{"STL 教程", "http://c.biancheng.net/stl/"},
{"Python 教程", "http://c.biancheng.net/python/"},
{"Java 教程", "http://c.biancheng.net/java/"} };
umap.clear(); // umap 容器清空,umap.size() = 0