一对基本类型的良好哈希函数

时间:2013-05-09 21:47:35

标签: c++ hash

我正在尝试为两个基本类型的std :: pair找出一个好的哈希函数。这就是我现在实施它的方式:

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)(数字翻转),它似乎也能工作。它们生成相同的哈希值,但值仍然成功插入到哈希映射中。有什么想法吗?

5 个答案:

答案 0 :(得分:5)

一般来说,散列容器总是必须处理这种情况(散列冲突)。他们可以使用几种方法,如链接和探测,其中任何一种都可能会损害性能。

相反,我建议使用boost::hash_combine来组合哈希,以便交换firstsecond不会生成相同的哈希值。

答案 1 :(得分:2)

以下是基于当前版本的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;
}

我实际上无法保证此功能背后的逻辑,但它看起来比这里提到的大多数选项更加坚固。

答案 2 :(得分:1)

假设stdext :: hash_value为第一个和第二个中的每一个提供了良好的散列值分布,那么如果不期望镜像对的发生率不成比例(例如(1,2),那么你所做的就很好了) )和(2,1))。如果您的数据集是 期望的那么多,那么您可以考虑调整哈希函数以强制它们不同。例如,反转第一个哈希值:

return ~stdext::hash_value<T>(rhs.first) ^ stdext::hash_value<T>(rhs.second);

我之所以提到这一点,只是因为你对镜像对表示担忧。如果您的输入在这方面接近随机,则^应该没问题。请记住,目标是尽量减少碰撞,而不是完全避免碰撞。

答案 3 :(得分:0)

正如其他人所说,哈希函数只影响哈希表的效率,而不是正确性。如果镜像对频繁,那么你的功能就不好了。由于在某些应用程序中这可能是一个问题,因此交换一个哈希值的上半部分和下半部分然后交换xor是合理的。许多其他方案都是可能的,但这个方案非常快速和简单。

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);
}

答案 4 :(得分:0)

只是为了它的乐趣,这是另一种简单直接解决问题的方法,特别是:

  • 如果firstsecond相同,则返回其公共哈希值
  • 否则,它会对值进行异或但是:
    • 为了防止h(a,b)与h(b,a)碰撞,它使用&lt; 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 - 减少分支可能会提高速度。

相关问题