【问题标题】:Hash function for basic struct基本结构的哈希函数
【发布时间】:2021-09-24 14:56:41
【问题描述】:

我有一个非常简单的 POD 结构,其中包含 3 个短裤,我计划在 unordered_set 中使用它数亿次。

这是我目前正在做的事情:

struct ps3 {
    short v1;
    short v2;
    short v3;

    bool operator==(const ps3& other) const {
        return v1 == other.v1
            && v2 == other.v2
            && v3 == other.v3;
    }
}

// Hash function:
size_t operator()(const ps3& p) const {
    return (static_cast<size_t>(*reinterpret_cast<const int*>(&p)) << 16) | p.v3;
}

哈希函数只返回 ps3 的值,因为它可以容纳在 8 个字节内。

(我看到here,对于基本类型,标准哈希函数只返回自身,所以如果它是一个值为 30 的 int,它将返回 30 的哈希)

我返回 ps3 的值,方法是获取前四个字节,移位 16,然后 OR 处理最后一个字节。

我想知道这种方法是否好用,是否有什么可以提高性能的方法(因为它被使用了数亿次,可能是数十亿次)

基准测试

我做了一些基准测试,结果如下:

  • 当前方法:1076ms
  • memcpy:1500ms
  • 按照@rturrado 的建议,使用hash&lt;short&gt;() 组合每个短片:876 毫秒

【问题讨论】:

  • *reinterpret_cast&lt;const int*&gt;(&amp;p)) &lt;&lt; 16 是未定义的行为。我建议使用memcpy 将结构复制到unsigned long long,然后散列/返回该整数。
  • 我很确定reinterpret_cast 的这种用法违反了严格的别名规则,这意味着该代码具有未定义的行为。执行此操作的正确方法是使用std::memcpy
  • 在 A Tour of C++ 一书中,他们建议对结构成员使用异或组合现有的哈希函数。在您的情况下,它将类似于hash&lt;short&gt;()(v1) ^ hash&lt;short&gt;()(v2) ^ hash&lt;short&gt;()(v3)
  • 很可能不会。所有数据都应该在缓存/寄存器中,所以应该很快。
  • 如果您担心性能,请不要使用std::unorderd_set。它基本上是 std::vector&lt;std::list&gt;std::list 是性能最差的容器之一。

标签: c++ hash


【解决方案1】:

根据 A Tour of C++ 中的 cmets,您自己的哈希的可能实现是:

struct ps3 { short v1; short v2; short v3; };

struct ps3_hash {
    size_t operator()(const ps3& other) const {
        return hash<short>()(other.v1) ^ hash<short>()(other.v2) ^ hash<short>()(other.v3);
    }
};

unordered_set<ps3, ps3_hash> my_set;  // set of ps3s using ps3_hash for lookup

【讨论】:

    猜你喜欢
    • 2011-02-27
    • 2017-08-27
    • 2015-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-17
    • 2010-12-07
    • 1970-01-01
    相关资源
    最近更新 更多