在上一节,咱们讲到:这是自定义类型做为map的Key的编程技法与原理。咱们这里先只谈技法,原理下次讲哈希表再去探讨。ios
联想标记数组算法,其实标记数组就是一种哈希,只是那是一种如下标(非负整型做为Key)的哈希表。unordered_map的底层实现就是哈希表实现的,这个能够联想类比标记数组!算法
回顾标记数组的作法!在得到标记下标的时候,也就是知道Key的时候,咱们要对数组中同为Key下标的数组元素进行操做。其实哈希表也差很少的,那么你们思考,什么样的类才能知足这个操做呢?编程
首先,须要到数组中查找是否已经标记了这个元素,若是没有加上标记,若是有就对标记的值(也就是Key-Value的Value)进行访问。那么,咱们的类就须要可以支持找到相同Key的方法,也就是“判等”方法,这经过重载运算符==实现!其实和Java的重写equal和hashcode方法差很少。数组
光有判等方法不够,为了提升效率,咱们能够先采用哈希算法,获得对应的哈希值。若是哈希值相同再判等,为何这样呢?是为了不哈希碰撞!bash
仍是上一篇博客的例子:ide
给定N个学生,用unordered_map存储,而且给学生成绩进行打分。实现的程序是:函数
#include <iostream> #include <unordered_map> #include <algorithm> using namespace std; class Student { friend ostream& operator<<(ostream& out, const Student& res); private: string name; int score; public: Student(string name_, int score_) : name(name_), score(score_) { } bool operator==(const Student& obj) const { return name == obj.name && score == obj.score; } string getName() const { return name; } int getScore() const { return score; } }; ostream& operator<<(ostream& out, const Student& res) { out << "Name : " << res.name << ",\tscore : " << res.score; return out; } class hashFunctor { public: size_t operator()(const Student& obj) const { return hash<string>()(obj.getName()) ^ hash<int>()(obj.getScore()); } }; char getRank(int score) { if (score >= 90) return 'A'; else if (score >= 60) return 'B'; else return 'C'; } int main() { unordered_map<Student, char, hashFunctor> umpStu; int n; cin >> n; for (int i = 0; i < n; ++i) { string curName; int curScore; cin >> curName >> curScore; umpStu[Student(curName, curScore)] = getRank(curScore); } for (auto it : umpStu) { cout << it.first << "\trank : " << it.second << endl; } return 0; }
输出结果是:spa
Name : jiangjy, score : 98 rank : A Name : zhangwj, score : 67 rank : B Name : zuozy, score : 98 rank : A Name : lifl, score : 86 rank : B Name : jiangzl, score : 48 rank : C
你们能够看到,这里是无序的状态了!因此unordered_map又叫无序关联容器。code
(一)自定义类型做为map的Key对象
须要重载小于运算符
(二)自定义类型做为unordered_map的Key
须要重载==运算符
须要一个仿函数(只重载函数调用运算符() 的类)做为参数构造unordered_map对象