在掌握unordered_map容器的基础下,我们开始unordered_multimap容器的学习。为什么要求有unordered_map容器的基础呢,原因在于unordered_multimap容器unordered_map容器十分“相似”,不同点在于unordered_map容器只允许存在唯一键,而unordered_multimap容器能够存储重复键,在理解unordered_map容器的基础上对比归纳这两个容器,能够对关联式容器有个宏观的视角,提高对容器的掌控力。如果读者没有unordered_map容器的基础,可跳转《C++ STL unordered_map容器入门》开始unordered_map容器的学习。

由于unordered_multimap容器允许存在相同键,在对比unordered_map容器的学习下读者有什么感想?要知道,unordered_map容器由于键的唯一性,能够通过'[]'、at()访问元素,但是对于unordered_multimap容器来说,重复键值意味着一个键对应多个值,不能形成一一对应的关系,所以unordered_multimap容器没有'[]'和at()。其他成员函数与unordered_map容器几乎相差无几,值得一提的是,equal_range()在unordered_multimap容器里能够大放异彩。接下来,我们就开始认识unordered_multimap容器吧:

创建unordered_multimap容器unordered_map容器没有差别,这里代码简单演示一下:

#include<bits/stdc++.h>//万能头,以效率为中心 
#include<string>
#include<unordered_map>//包含头文件,养成好习惯 
/*multimap初始化 */
using namespace std;
void test()
{
unordered_multimap<int,int> ummp1;//直接创建
unordered_multimap<int,int> ummp2{{1,1,},{2,2},{3,3},{4,4},{5,5}} ;//初始化列表
unordered_multimap<int,int> ummp3(ummp2) ;//拷贝构造
unordered_multimap<int,int> ummp4;
ummp4=ummp2;//'='运算符重载 
unordered_multimap<int,int> ummp5(ummp2.begin(),ummp2.end());//通过迭代器区间进行初始化 
}
int main(){
    test();
    return 0;
}

代码编译成功,我们总共有5种方法创建和初始化unordered_multimap容器。

unordered_multimap容器的成员函数相比unordered_map没有at(),同时也未能重载'[]'所以不能使用'[]'。下面我们通过表格的形式展示unordered_multimap的常用成员函数:

函数参数功能
empty()检查容器是否为空
size()返回元素数量
max_size()返回可容纳的最大元素数
begin()返回指向起始的迭代器
end()返回指向末尾的迭代器
cbegin()返回指向起始的常量迭代器
cend()返回指向末尾的常量迭代器
clear()清空所有元素
bucket_count()返回桶的数量
max_bucket_count()返回桶的最大数量
load_factor()返回负载因子
max_load_factor()返回最大负载因子
hash_function()返回哈希函数对象
key_eq()返回键相等性判断函数对象
insert()
const value_type& value插入元素
InputIt first, InputIt last插入迭代器范围内的元素
initializer_list<value_type> ilist插入初始化列表中的元素
emplace()Args&&... args原位构造元素
emplace_hint()const_iterator hint, Args&&... args在提示位置原位构造元素
erase()const_iterator pos删除指定位置的元素
const key_type& key删除所有键为key的元素
const_iterator first, const_iterator last删除迭代器范围内的元素
find()const key_type& key查找键为key的元素
count()const key_type& key返回键为key的元素数量
equal_range()const key_type& key返回键为key的元素范围
bucket_size()size_type n返回第n个桶的大小
bucket()const key_type& key返回键key所在的桶编号
rehash()size_type count设置桶数为count并重新哈希
reserve()size_type count预留空间至少容纳count个元素

对于unordered_multimap容器,它是没有lower_bound()和upper_bound(),但是有equal_range(key),通过它我们能够找到键==key的所有键值对。如果读者不理解无序关联式容器的底层构造,此时心里会想,unordered_multimap容器不是以“无序”著称吗,元素分散排列,它是如何通过equal_range(key)找到所有键==key的呢?有这个疑惑的读者可跳转《深度剖析C++ STL无序关联式容器的底层构造》寻求答案。下面我们通过代码来学习equal_range(key):

#include<bits/stdc++.h>//万能头,以效率为中心 
#include<string>
#include<unordered_map>//包含头文件,养成好习惯 
/*unordered_multimap*/
using namespace std;
/*equal_range()*/
void test()
{
unordered_multimap<int ,string> ummp{{9,"Dptcpp"},{1,"编程问答"},{9,"计算机二级C语言"},{4,"数据结构教程"},{9,"Java教程"}};//建议这样初始化 ,直观具体
/*equal_range()等于key的迭代器区间 */
cout << "equal_range()找到键==Key的区间: \n";
auto range = ummp.equal_range(9) ;//auto省略了:pair<unordered_multimap<string,string>::iterator,unordered_multimap<string,string>::iterator>
for(auto it = range.first;it!=range.second;++it) //迭代器遍历 
{
cout << it->second <<'\n';
}
}
int main(){
    test();
    return 0;
}

编译结果如下:

equal_range()

当然,学习unordered_multimap容器,我们还需要学习其关于哈希的成员函数的使用技巧。在已知键值对数量n的情况下,我们可以通过reserve()来预存比n稍大的空间;对于负载因子的变化,如果我们想节省空间,则尽量控制在0.8-1.0之间,如果我们着眼于访问效率,则尽量控制在0.5-0.75之间。

总结:unordered_multimap容器unordered_map容器需要对比起来学习,操作unordered_multimap容器就不能使用'[]'和at(),而且要牢牢掌握equal_range()这个函数,读者需勤加练习,反复记忆和实践。

点赞(0)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)