本章我们总共学习无序关联式容器:unordered_map容器、unordered_multimap容器、unordered_set容器、unordered_multiset容器,他们的底层都是基于哈希表的结构封装起来的一个类。在存储基础数据类型时,键(key)能够通过哈希函数转为哈希值(数据类型为size_t),当我们的键为自定义数据类型时,就需要我们重新定义哈希函数和重载operator'=='运算符。哈希函数一般是通过仿函数来实现的。仿函数重写哈希函数时,要求我们的哈希函数能够让键均匀分布、确定是唯一的键和方便计算,一般是通过位移异或组合法来合成哈希值的。下面让我们通过unordered_map容器来装user结构体,具体分析如何重载“==”和重写哈希函数:
#include<iostream> #include<string> #include<unordered_map> /*自定义哈希函数*/ using namespace std; struct user { bool operator==(const user&u)const//const不能丢 { return m_s==u.m_s&&m_age==u.m_age&&m_gender==u.m_gender; } user(string s,int age,string gender):m_s(s),m_age(age),m_gender(gender){}; string m_s; int m_age; string m_gender; }; struct fhash { size_t operator()(const user&u)const { /*组合所有字段的哈希值,让每个成员变量参与分配*/ size_t h1 = hash<string>{}(u.m_s); size_t h2 = hash<int>{}(u.m_age); size_t h3 = hash<string>{}(u.m_gender); /*经典操作*/ /*通过'<<'位移和'^'按位异或,高效返回尽量“独立 ”的哈希值,避免哈希冲突*/ return h1^(h2<<1)^(h3<<2); } }; void test() { unordered_map<user,int,fhash> ump; ump.insert({{"dot01",18,"男"},1}); ump.insert({{"dot02",18,"男"},2}); ump.insert({{"dot03",18,"男"},3}); ump.insert({{"dot04",18,"男"},4}); ump.insert({{"dot05",18,"男"},5}); } int main(){ test(); return 0; }
代码成功编译!
总结:对于无序关联式容器,当键为自定义数据类型时,就需要我们重新定义哈希函数和重载operator'=='运算符,运算符重载不难,但是需要记住位移异或组合法来合成哈希值。
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程