为什么std :: hash <int>似乎是身份函数

时间:2016-07-11 10:39:40

标签: c++ debugging c++11 identity stdhash

#include <iostream>

int main() {
    std::hash<int> hash_f;
    std::cout << hash_f(0) << std::endl;
    std::cout << hash_f(1) << std::endl;
    std::cout << hash_f(2) << std::endl;
    std::cout << hash_f(3) << std::endl;
}

我用“g ++ main.cpp -std = c ++ 11”编译,结果是:

0
1
2
3

为什么会这样?我没有使用任何库,也没有专门的散列函数。

附录:我想为int的unordered_set的unordered_set定义散列,其中一个集合的散列是其组件散列的总和,但如果它只是标识它并不酷,因为{2,4}的散列是与{1,5}的哈希值相同。避免这种情况的最简单方法可能是使用std :: hash double函数。

3 个答案:

答案 0 :(得分:10)

它似乎是它的身份,它被允许作为它的独特...... 来自cpp reference

  

实际的散列函数是依赖于实现的,除了上面指定的那些之外,不需要满足任何其他质量标准。值得注意的是,一些实现使用简单(标识)散列函数将整数映射到自身。换句话说,这些散列函数被设计为与无序关联容器一起使用,但不是作为加密散列。 ....

答案 1 :(得分:7)

哈希函数intint似乎是完全合理的,并且不清楚为什么你会对此感到惊讶。执行任何进一步的计算将毫无意义。事实上,这在任何意义上都是完美哈希

请记住,std::hash应该(几乎唯一)识别值,而不是加密它们。

只有当你想要散列大于散列本身的类型(比如uint9999999_t)时才需要做一些工作来压缩&#34;&#34;将值转换为哈希的大小。

答案 2 :(得分:4)

其他答案很好地涵盖了身份功能背后的基本原理。解决你的附录:

  

我想将unordered_set的哈希值定义为其组件哈希值的总和,但如果它只是身份识别它并不酷,因为{2,4}的哈希值与{1,5}的哈希值相同。避免这种情况的最简单方法可能是使用std :: hash函数。

如您所见,使用+运算符组合哈希值并不是最佳选择。为了更加健壮,您可以使用XOR(^)运算符,或者从所采用的方法中获取灵感,例如boost::hash_combinedetails in this SO post):

seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);

作为一个例子,对于你的两个整数对(1,5 / 2,4)和一个seed为0,这将是

uint32_t seed = 0;
seed ^= 1 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
seed ^= 5 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
// 3449077526

uint32_t seed = 0;
seed ^= 2 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
seed ^= 4 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
// 3449077584