对于具有3个无符号字符和int的for,对于unordered_map,有什么好的哈希函数?

时间:2012-11-15 00:13:34

标签: c++ unordered-map hash-function

我只想使用一个unordered_map和我的struct作为键,因为我不需要任何排序..但我只是找不到所有那些哈希的东西..

作为一个相关的问题..当ppl比较无序和有序的地图时,他们从不谈论散列函数,那怎么可能?不好的哈希函数会使无序映射比映射慢吗? (完全由于散列函数)

struct exemple{

  unsigned char a,b,c;
  unsigned int n;

  bool operator == ( const exemple & other) const {..}
};

namespace std {
template <>
struct hash<exemple> : public std::unary_function<const exemple &, std::size_t>
{
    inline std::size_t operator()(const exemple & exemple_p ) const
    {
        return 0;// what do I do
    }
};

}

CNC中 a,b,c只能有'a','b','c'或'd'的值,而n在3到60之间变化。

4 个答案:

答案 0 :(得分:4)

你在哈希函数中所做的事情取决于你得到的值,而不一定取决于它们的类型。如果所有四个数据成员都包含均匀分布的每个值,我会将这两个字符组合成unsigned long并返回xoring两个值的结果:

typedef unsigned long ulong;
return n ^ (ulong(a << 16) | ulong(b << 8) | ulong(c));

肯定是一个哈希函数。它是否运作良好是一个不同的问题。您也可以将结果与std::hash<unsigned long>合并。

答案 1 :(得分:2)

这是一个基线哈希函数:

unsigned long long h = (n << 24) | (a << 16) | (b << 8) | c;
return std::hash(h);

即,只需将成员打包到unsigned long long,然后将工作卸载到std::hash。在int为32位宽且long long为64位的常见情况下,假设您的字符不是负数,则会使用对象中的所有信息进行散列。

答案 2 :(得分:2)

struct整体视为一串字节(准确地说是7)。您可以在这7个字节上使用任何可接受的通用字符串哈希函数。下面是应用于您的示例的FNV(Fowler / Noll / Vo)通用位串散列函数(在给定的散列仿函数类中):

inline std::size_t operator()(const exemple& obj ) const
{
  const unsigned char* p = reinterpret_cast<const unsigned char*>( &obj );
  std::size_t h = 2166136261;

  for (unsigned int i = 0; i < sizeof(obj); ++i)
    h = (h * 16777619) ^ p[i];

  return h;
}

注意我是如何将对exemple结构(obj)的引用转换为指向const unsigned char的指针,以便我可以逐个访问结构的字节,并且我将它视为不透明的二进制对象。请注意sizeof(obj)实际上可能是8而不是7,具体取决于编译器的填充(这意味着结构中某处有垃圾填充字节,可能在cn之间。如果您需要,您可以重写哈希函数以迭代abc,然后按顺序(或任何顺序)迭代n的字节,这将消除任何填充字节(可能存在或可能不存在)对struct的哈希值的影响。

是的,错误的哈希函数会使unordered_map慢于ordered_map。这并不总是被讨论,因为假定使用unordered_map的那些广义的快速算法(如上面给出的FNV哈希),在这些情况下,通常unordered_map比{ordered_map更快。 1}}代价是按顺序迭代容器元素的能力。但是,是的,你必须为你的数据使用一个好的哈希函数,通常它足以使用这些众所周知的哈希之一。但是,最终,每个散列函数都有其弱点,具体取决于输入数据(此处为exemple结构的内容)分布。

可以在Eternally Confuzzled找到关于广义散列和示例散列函数的很好的讨论,包括类似于我给你的C风格的FNV哈希。

答案 3 :(得分:0)

boost::hash_combine专为此目的而设计:

std::size_t hash = 0;
for (const auto& value : {a, b, c}) {
    boost::hash_combine(hash, value);
}
boost::hash_combine(hash, n);
return hash;