0.自定义类型需要满足的条件
我们需要为自定义类型Key
实现一个Function Object
,他需要遵守以下条件:
- 返回类型为
std::size_t
- 接受单个参数,参数类型为
Key
,一般我会习惯使用const Key& key
- 他是一个常量成员函数
- 他不会抛出异常
- 对于相同的
Key
,我们需要返回相同的值;对于不同的Key
,我们需要尽量减小collision的发生
听上去很多要求,其实很简单,我们有两种方法来实现以上要求,下面一一阐述。
1.std::hash的template specialization
我们选择std::pair<std::string,int>
作为哈希表的Key
namespace std{
template <>
struct hash<std::pair<std::string,int >>{
std::size_t operator()(const std::pair<std::string, int>& p)const noexcept {
return std::hash<std::string>()(p.first)^std::hash<int>()(p.second);
}
};
}
接下来我们就可以直接使用了
class UserDefinedHash{
public:
UserDefinedHash(){
}
void addData(const std::pair<std::string,int>& key,int val){
templateSpecilization[key]=val;
}
int showData(const std::pair<std::string,int>& key){
auto re=templateSpecilization.find(key);
if(re != templateSpecilization.end())
return templateSpecilization.at(key);
return -1;
}
private:
std::unordered_map<std::pair<std::string,int>,int> templateSpecilization;
};
2.使用自定义Function Object
struct MyHash{
std::size_t operator()(const std::pair<int,int>& p) const noexcept {
return std::hash<int>()(p.first)^std::hash<int>()(p.second);
}
};
在使用时,制定std::unordered_map
的第三个参数为MyHash
即可
class UserDefinedHash{
public:
UserDefinedHash(){
}
void addData(const std::pair<int,int>& key,int val){
functor[key]=val;
}
private:
std::unordered_map<std::pair<int,int>,int,MyHash> functor;
};
3.其他的思考
在选择哈希函数时,上面第二个例子其实并不好,因为当Key
为{1,1}
~{n,n}
时,返回的哈希经过XOR
运算,结果都是一样的,所以我们在选择哈希函数时最好慎重考虑,避免一些明显的错误,如果有条件可以使用boost::hash_combine
.