很好的哈希函数对基本类型
Good hash function for pair of primitive types
我试图找出一个好的哈希函数为std::对两个基本类型。这是我现在实现它的方式:
template<typename T, typename U>
std::size_t operator()(const std::pair<T,U> &rhs) const
{
return stdext::hash_value<T>(rhs.first) ^ stdext::hash_value<U>(rhs.second);
}
它似乎工作,即使我有两对,如(1,2)和(2,1)(数字翻转)。它们生成相同的哈希值,但这些值仍然成功地插入到哈希映射中。任何想法吗?
一般来说,散列容器总是必须处理这种情况(散列冲突)。他们可以使用一些方法,如链接和探测,其中任何一种都可能损害性能。
相反,我建议使用boost::hash_combine
来组合哈希,这样交换first
和second
不会生成相同的哈希。
下面是基于当前版本boost文档的hash_combine
实现:(http://www.boost.org/doc/libs/1_53_0/doc/html/hash/reference.html boost.hash_combine)
template<typename T> void hash_combine(size_t & seed, T const& v) {
seed ^= stdext::hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
你可以这样使用:
template<typename T, typename U>
std::size_t operator()(const std::pair<T,U> &rhs) const {
size_t retval = stdext::hash_value<T>(rhs.first);
hash_combine(retval, rhs.second);
return retval;
}
我不能保证这个函数背后的逻辑,但它看起来比这里提到的大多数选项更可靠。
假设stdext::hash_value为first和second提供了一个很好的散列值分布,如果您不期望出现不成比例的高镜像对(例如(1,2)和(2,1)),那么您所做的是可以的。如果您的数据集确实期望有很多这样的数据集,那么您可以考虑调整散列函数,使它们不同。例如,反转第一个哈希值:
return ~stdext::hash_value<T>(rhs.first) ^ stdext::hash_value<T>(rhs.second);
我提到这个只是因为你表达了对镜像对的关注。如果你的输入在这方面接近随机,那么^就可以了。请记住,目标是尽量减少碰撞,而不是完全避免碰撞。
正如其他人所指出的,哈希函数只影响哈希表的效率,而不影响正确性。只有当镜像对频繁出现时,函数才会出现问题。由于在某些应用程序中这可能是一个问题,因此交换一个哈希值的上下半字,然后进行异或是合理的。许多其他方案都是可行的,但这个方案非常快速和简单。
template<typename T, typename U>
std::size_t operator()(const std::pair<T,U> &rhs) const
{
const int h = sizeof(size_t) * 8 / 2;
size_t a = stdext::hash_value<T>(rhs.first);
return ((a << h) | (a >> h)) ^ stdext::hash_value<U>(rhs.second);
}
只是为了好玩,这里有另一种简单且直接解决问题的方法,特别是:
- 如果
first
和second
是相同的,它返回它们的公共哈希值 - 否则,它对值进行xor,但是:
- 为了防止h(a, b)与h(b, a)发生碰撞,使用了<b在h(a)^h(b)和h(a)^h(~b)之间进行选择>
1 template<typename T, typename U>
2 std::size_t operator()(const std::pair<T,U> &rhs) const
3 {
4 std::size_t a = stdext::hash_value<T>(rhs.first);
5 return rhs.first == rhs.second ? a :
6 a ^ (rhs.first < rhs.second ? stdext::hash_value<U>(rhs.second)
7 : stdext::hash_value<U>(~rhs.second));
8 }
说真的,我建议遵循Mark B的建议,使用boost::hash_combine——更少的分支可能会提高速度。
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 将C++子类成员函数(虚拟实现)传递给 C 类型函数指针
- C++ 这里有一个返回 (24) 的布尔返回类型函数
- 使用SFINAE来检测void返回类型函数的存在
- 使用此类型函数有什么优势
- 为什么此函数通过类型函数指针调用后,呼叫明智地行为
- 如何使用无类型函数指针调用C++成员函数
- 模板返回类型函数如何在C++中工作
- 具有通用类型函数的动态库[C ]
- 如何在返回类型函数模板的专用化中使用派生类型?( "couldn't infer template argument" )
- Bon appetit :从 int 返回类型函数在 main() 中打印字符串
- 对于需要其他模板参数的类型函数的部分模板专业化
- c++错误的参数类型-函数指针
- 延迟评估模板类型函数
- 在引用或指针返回类型函数上输入
- 具有指针数据类型的非类型函数模板参数
- STL中使用的C++自定义比较类型(函数谓词与较少结构)
- C++模板基类的非类型函数模板的 using 声明
- 字符串到类型函数,模板专用化使调用统一
- 自由类型函数可以接受 Unicode 文件名吗?