14
#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 双精度函数。

4

3 回答 3

11

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

实际的散列函数是依赖于实现的,并且不需要满足除上面指定的那些之外的任何其他质量标准。值得注意的是,一些实现使用将整数映射到自身的普通(身份)哈希函数。换句话说,这些散列函数旨在与无序关联容器一起使用,但不能用作加密散列。……

于 2016-07-11T10:47:39.883 回答
7

散列函数 →<code>int 是恒等函数似乎是完全合理的int,但不清楚你为什么对此感到惊讶。执行任何进一步的计算都是没有意义的。事实上,从任何意义上来说,这都是一个完美的散列

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

只有当您想要散列大于散列本身的类型(例如uint9999999_t)时,您才需要做一些工作来将值“压缩”成散列的大小。

于 2016-07-11T11:00:18.703 回答
6

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

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

如您所见,使用+运算符组合散列并不是最好的主意。为了更健壮,您可以使用 XOR ( ^) 运算符,或者从所采用的方法中获取灵感,例如boost::hash_combinethis SO post 中的详细信息):

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

例如,对于您的两个整数对 (1,5 / 2,4) 和seed0 的 a,这可以解决

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
于 2016-07-11T12:01:03.097 回答