unordered_map自定义数据结构
文章目录
1. 说明
一般来说,我们经常使用的STL 哈希的使用方法如下👇
unordered_set<int> uset;
unordered_map<int, unordered_set<int>> my_ump; // 拉链法
但是当我们更换数据结构(将key对应的int,更换为自定义数据结构时)时,会报错👇
2. 自定义数据结构(或者类,或者容器等)使用方法
2.1 自定义数据结构报错
这里使用的是举例说明,假设我们有如下数据结构:(其实是一个160bit的“指纹”(哈希值))
typedef struct SHA1FP {
uint64_t fp1;
uint32_t fp2, fp3, fp4;
} SHA1FP_s;
如果和之前一样,使用如下定义👇
unordered_set<SHA1FP_s> uset; //将会报错
将会报错如下👇(即找不到对应的数据结构——哈希方法、对比是否最终相等的方法等)
std::unordered_set<SHA1FP_s> uset
the default constructor of "std::unordered_set<SHA1FP_s, std::hash<SHA1FP_s>, std::equal_to<SHA1FP_s>, std::allocator<SHA1FP_s>>" cannot be referenced -- it is a deleted functionC/C++(1790)
2.2 使用自定义数据结构的方法
根据之前的报错信息,自定义哈希方法、对比是否相同的方法。
2.2.0 可以运行的uset定义方法
unordered_set<SHA1FP_s, Hasher, Euqaler> uset;
后面将分别解释Hasher
(自定义哈希方法) 和Equaler
(自定义数据结构是否相同)的含义。
2.2.1 自定义哈希方法
struct Hasher{
size_t operator()(SHA1FP_s& a) const {
return a.fp1;
}
};
2.2.2 对比是否相同
因为hash是可能会碰撞的(可能存在两个不同的sha1,分别是a和b,a.fp1 == b.fp1 但是a != b)——需要判断所有值是否相同
struct Euqaler{
bool operator()(SHA1FP_s& a, SHA1FP_s& b) const {
return ((a.fp1 == b.fp1) && (a.fp2 == b.fp2) && (a.fp3 == b.fp3) && (a.fp3 == b.fp3));
}
};
3. 完整代码
3.1 运行方法
将下面代码复制到hash_customize.cpp
,然后使用如下命令即可编译成功👇
g++ hash_customize.cpp -o hash_customize
3.2 完整代码
// g++ hash_customize.cpp -o hash_customize
#include <iostream>
#include <unordered_set>
#include <vector>
using namespace std;
typedef struct SHA1FP {
uint64_t fp1;
uint32_t fp2, fp3, fp4;
} SHA1FP_s;
struct Hasher{
size_t operator()(SHA1FP_s& a) const {
return a.fp1;
}
};
struct Euqaler{
bool operator()(SHA1FP_s& a, SHA1FP_s& b) const {
return ((a.fp1 == b.fp1) && (a.fp2 == b.fp2) && (a.fp3 == b.fp3) && (a.fp3 == b.fp3));
}
};
int main() {
// test_customize_umap();
unordered_set<SHA1FP_s, Hasher, Euqaler> uset;
exit(0);
}
4. 例子2:vector当key
4.1 运行方法
将下面代码复制到hash_customize.cpp
,然后使用如下命令即可编译成功👇
g++ hash_customize.cpp -o hash_customize
使用如下命令运行👇
./hash_customize
4.2 完整代码(请注意看注释部分)
// g++ hash_customize.cpp -o hash_customize
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;
void print_vec(const vector<int>& vec) {
for (auto elem : vec) {
cout << elem << " ";
}
cout << endl;
}
// 这里直接使用vec中的第一个元素作为hash value(这样做并不好,碰撞率会比较高,但是十分直观),另一种更加高效的方式在my_Hasher中
struct Hasher{
size_t operator()(const vector<int>& a) const {
return a[0];
}
};
// 更加高效的自定义hash方法(用来代替Hasher)
struct my_Hasher{
size_t operator ()(const vector<int>& a) const {
hash<int> hsh;
int seed = 0;
for (auto elem : a) {
seed ^= hsh(elem) + 0x803923 + (seed << 5) + (seed >> 3); //这里左移多少位,右移多少位,还有加0x803923都是随便写的,也不一定非是这样写(不一定非要左移或者右移,总之就是一个函数,尽量避免碰撞)
}
return seed;
}
};
struct Equaler{
bool operator()(const vector<int>& a, const vector<int>& b) const {
return a == b;
}
};
void test_customize_umap() {
unordered_map<vector<int>, vector<int>, Hasher, Equaler> ump;
vector<int> helo = {1,2,3};
ump[helo] = helo;
for (auto elem : ump) {
print_vec(elem.first);
print_vec(elem.second);
}
}
int main() {
test_customize_umap();
// unordered_set<SHA1FP_s, Hasher, Euqaler> uset;
exit(0);
}
4.3 运行结果
levi@LEVI1:~/code$ ./hash_customize
1 2 3
1 2 3