在了解哈希表存储结构的基础上,本节将具体分析 C++ STL 无序容器(哈希容器)底层的实现原理。在阅读本节内容之前,读者需了解哈希表存储结构的原理,可猛击《哈希表(散列表)详解》一节。
可以看到,当使用无序容器存储键值对时,会先申请一整块连续的存储空间,但此空间并不用来直接存储键值对,而是存储各个链表的头指针,各键值对真正的存储位置是各个链表的节点。其中,Pi 表示存储的各个键值对。
不仅如此,在 C++ STL 标准库中,将图 1 中的各个链表称为桶(bucket),每个桶都有自己的编号(从 0 开始)。当有新键值对存储到无序容器中时,整个存储过程分为如下几步:注意,STL 标准库通常选用 vector 容器存储各个链表的头指针。
负载因子 = 容器存储的总键值对 / 桶数
默认情况下,无序容器的最大负载因子为 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() | 返回当前容器使用的哈希函数对象。 |
#include <iostream> #include <string> #include <unordered_map> using namespace std; int main() { //创建空 umap 容器 unordered_map<string, string> umap; cout << "umap 初始桶数: " << umap.bucket_count() << endl; cout << "umap 初始负载因子: " << umap.load_factor() << endl; cout << "umap 最大负载因子: " << umap.max_load_factor() << endl; //设置 umap 使用最适合存储 9 个键值对的桶数 umap.reserve(9); cout << "*********************" << endl; cout << "umap 新桶数: " << umap.bucket_count() << endl; cout << "umap 新负载因子: " << umap.load_factor() << endl; //向 umap 容器添加 3 个键值对 umap["Python教程"] = "http://c.biancheng.net/python/"; umap["Java教程"] = "http://c.biancheng.net/java/"; umap["Linux教程"] = "http://c.biancheng.net/linux/"; //调用 bucket() 获取指定键值对位于桶的编号 cout << "以\"Python教程\"为键的键值对,位于桶的编号为:" << umap.bucket("Python教程") << endl; //自行计算某键值对位于哪个桶 auto fn = umap.hash_function(); cout << "计算以\"Python教程\"为键的键值对,位于桶的编号为:" << fn("Python教程") % (umap.bucket_count()) << endl; return 0; }程序执行结果为:
umap 初始桶数: 8
umap 初始负载因子: 0
umap 最大负载因子: 1
*********************
umap 新桶数: 16
umap 新负载因子: 0
以"Python教程"为键的键值对,位于桶的编号为:9
计算以"Python教程"为键的键值对,位于桶的编号为:9
关于表 2 中成员方法的具体语法和用法,都很简单,不再过多赘述,感兴趣的读者可自行翻阅 C++ STL手册。
Copyright © 广州京杭网络科技有限公司 2005-2024 版权所有 粤ICP备16019765号
广州京杭网络科技有限公司 版权所有