【问题标题】:What should hash for a custom datatype return in C++?C++ 中自定义数据类型的哈希值应该返回什么?
【发布时间】:2020-10-14 14:46:07
【问题描述】:

我想在unordered_set 中使用我的数据类型。它没有用,但this SO question 帮助理解了我需要做的事情。
This answer 但是让我很困惑我应该在哈希结构中放入什么。
我的哈希现在应该返回x.name.size() 还是x.hash

我的数据类型:

struct State {
  std::string name;
  std::size_t hash = std::hash<std::string>{}(name);

  bool operator==(const State &rhs) const;
  bool operator!=(const State &rhs) const;
  };

我应该使用 A 还是 B ?

namespace std {
template<>
struct hash<State>{

  typedef State argument_type;
  typedef std::size_t  result_type;

  size_t operator()(const foundation::State& x) const{
    // A.) return x.name.size();
    // B.) return x.hash;
  }
};
}

【问题讨论】:

  • return x.hash; 会起作用,但要注意将哈希存储为成员是一种权衡。每次State 的状态发生变化时,您都需要显式刷新该哈希值。从技术上讲,return x.name.size(); 也可以,但它可能会导致你的系列表现非常糟糕。
  • 在任何情况下,您的哈希都是字符串的长度,您要求将其存储为成员还是在每次调用时重新计算?

标签: c++


【解决方案1】:

散列函数的主要功能是成为一个很好的代理,无论两个对象是否可能相同或绝对不同。

如果返回x.name.size(),具有相同数量字母的状态对象将具有相同的哈希码。如果将这些对象粘贴在 unordered_set 中,这将导致大量碰撞。这意味着它必须依靠相对昂贵的比较来确定两个对象实际上是否相同。

如果您改为返回x.hash(它应该是x.name 的哈希值(希望永远不会改变)),名称的任何差异都会导致哈希值大不相同。根据所使用的散列函数,两个不同的对象只有 2^128 分之一(或 32 位系统上 2^64 分之一)发生碰撞的机会。因此,您的 unordered_set 很可能能够均匀地传播结果,并使您更接近那个神奇的 O(1) 查找时间。

【讨论】:

    【解决方案2】:

    如果您返回 x.name.size() 作为对象的哈希值,您实际上是在说两件事:

    • 您希望 name 为“abc”、“def”、“123”的对象都具有相同的哈希值。
    • 您不希望其他字段作为您对象哈希码的贡献者参与。

    从性能的角度来看,这里的第一点是有问题的。这将导致哈希表中不同对象的分布非常差,因为您使用的是长度而不是名称的内容。

    第二个含义可能会或可能不会产生明显的影响,但根据给定的信息,不确定它会朝哪个方向发展。

    【讨论】:

      【解决方案3】:

      您应该返回与您的== 一致的内容。

      我假设您已将其定义为

      bool State::operator==(const State &rhs) const
      {
          return (name == rhs.name);
      }
      

      在这种情况下是最自然的

      size_t std::hash<foundation::State>::operator()(const foundation::State& x) const {
          return std::hash<std::string>{}(x.name);
      }
      

      如果您有更多成员参与==,他们也应该参与std::hash。组合哈希的策略有很多。

      我建议不要拥有数据成员std::size_t hash

      【讨论】:

        猜你喜欢
        • 2020-12-30
        • 2020-07-08
        • 2013-02-13
        • 2021-07-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-15
        相关资源
        最近更新 更多