C++ 什么';对于具有3个无符号字符和一个int的结构,对于无序的_映射,它是一个很好的哈希函数?

C++ 什么';对于具有3个无符号字符和一个int的结构,对于无序的_映射,它是一个很好的哈希函数?,c++,unordered-map,hash-function,C++,Unordered Map,Hash Function,我只想使用一个无序的映射,以我的结构作为键,因为我不需要任何排序。但是我就是找不到自己有所有的散列内容 作为一个侧面相关的问题,当ppl比较无序映射和有序映射时,他们从不谈论哈希函数,这怎么可能呢?坏的散列函数不能使无序映射比映射慢吗?(仅由于哈希函数) struct示例{ 无符号字符a、b、c; 无符号整数n; 布尔运算符==(常量示例和其他)常量{..} }; 名称空间标准{ 样板 结构哈希:公共std::一元函数 { 内联std::size\u t运算符()(常量示例和示例p)常量 { 返

我只想使用一个无序的映射,以我的结构作为键,因为我不需要任何排序。但是我就是找不到自己有所有的散列内容

作为一个侧面相关的问题,当ppl比较无序映射和有序映射时,他们从不谈论哈希函数,这怎么可能呢?坏的散列函数不能使无序映射比映射慢吗?(仅由于哈希函数)

struct示例{
无符号字符a、b、c;
无符号整数n;
布尔运算符==(常量示例和其他)常量{..}
};
名称空间标准{
样板
结构哈希:公共std::一元函数
{
内联std::size\u t运算符()(常量示例和示例p)常量
{
返回0;//我该怎么办
}
};
}

-编辑-
a、 b,c只能有值“a”、“b”、“c”或“d”,n的变化范围为3到60。

这里有一个基线哈希函数:

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

unsigned long long h=(n在哈希函数中执行的操作取决于得到的值,而不一定取决于它们的类型。如果所有四个数据成员都包含均匀分布的每个值,我会将这两个字符组合成一个
unsigned long
,并返回对这两个值进行异或运算的结果:

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

返回n^(ulong(a将您的
struct
视为一个字节字符串(精确地说是7)。您可以在这7个字节上使用任何可接受的通用字符串哈希函数。以下是应用于示例的FNV(Fowler/Noll/Vo)通用位字符串哈希函数(在给定的哈希函数类中):

inline std::size\u t operator()(const-example&obj)const
{
const unsigned char*p=重新解释强制转换(&obj);
标准尺寸=2166136261;
for(无符号整数i=0;i
请注意,我是如何将对
example
结构(
obj
)的引用转换为指向
const unsigned char
的指针的,以便可以逐个访问结构的字节,并将其视为不透明的二进制对象。请注意
sizeof(obj)
实际上可能是8而不是7,这取决于编译器的填充(这意味着在结构中的某个地方有一个垃圾填充字节,可能介于
c
n
之间。如果需要,可以重写哈希函数,依次遍历
a
b
c
,然后依次遍历
n
的字节(或任意顺序),这将消除任何填充字节(可能存在也可能不存在)对
结构的哈希的影响

是的,一个坏的散列函数会使
无序映射
有序映射
慢。这并不总是讨论的,因为上面给出的FNV散列这样的通用快速算法被假定为是那些使用
无序映射
的人使用的,在这些情况下,
无序映射
通常比
无序映射
快rdered_map
以按顺序迭代容器元素的能力为代价。但是,是的,您必须为数据使用一个好的哈希函数,通常使用这些众所周知的哈希函数就足够了。但是,最终,每个哈希函数都有其弱点,这取决于输入数据的大小(这里是
示例
结构的内容)分布

关于广义散列和示例散列函数的详细讨论可以在上找到,包括一个类似于我给您的C风格FNV散列。

就是为此目的而设计的:

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

你需要自己编写散列函数吗?这是两个截然不同的问题。请一次发布其中一个。@evanmcdonnal你是什么意思?如果我不提供散列函数,无序映射不会编译。是的,但是你可以使用已经存在的散列库的逻辑。例如,假设我有一些字符串散列函数
散列(string)
我可以创建一个函数,将
int
转换为一个字符串,然后将其与三个
字符连接起来,然后使用
返回散列结束函数(stringijustmake)
这与自己实际编写低级散列逻辑不同。首先,您删除了
一元函数
。这东西从永远开始就毫无用处了。关于组合散列:为什么C++11要使用
散列组合
?这是
boost::hash
的一个很好的特性。哦,我明白了……我应该提一下我的unsigned字符只能计算a、b、c或d值…而n从~3到60不等。你是说你有43*60~=2^12==4096个值吗?在这种情况下,不用麻烦使用哈希映射,而是使用数组…@pmr:但是它应该可以工作:
std::hash hasher;unsigned long hash=hasher(value);
。从外观上看,您试图将
unsigned long
作为构造函数参数传递给
std::hash
,即
std::hash(value)
。当然,这不起作用。
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;
}
std::size_t hash = 0;
for (const auto& value : {a, b, c}) {
    boost::hash_combine(hash, value);
}
boost::hash_combine(hash, n);
return hash;