假设我有用户定义的类型
struct Key
{
short a;
int b,c,d
}
我想在无序地图中使用它作为关键。什么是一种好的(有效的)散列技术。鉴于我可能需要做很多阅读。 是否有使用hash_combine或hash_append的东西我应该做什么?
答案 0 :(得分:3)
最安全的路径可能是为原子类型重用标准哈希并按照建议将它们组合起来。 AFAIK标准中没有散列组合例程,但Boost确实提供了一个:
#include <boost/functional/hash.hpp>
#include <functional>
namespace std
{
template<>
struct hash<Key>
{
public:
std::size_t
operator()(Key const& k) const
{
size_t hash = 0;
boost::hash_combine(hash, std::hash<short>()(k.a));
boost::hash_combine(hash, std::hash<int>()(k.b));
boost::hash_combine(hash, std::hash<int>()(k.c));
boost::hash_combine(hash, std::hash<int>()(k.d));
return hash;
}
};
}
如果依赖Boost不是一个选项,他们的哈希组合例程足够小,可以合理无瑕地被盗:
template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
如果你的四个积分值是纯粹随机的(例如,他们可以在相同的概率范围内取任何值),这可能非常接近于最优。如果您的值更具体 - 例如,一个只有三个可能的值,或者它们是相关的 - 您可以稍微好一点。但是,这在任何情况下都会表现“好”。
无论如何,我认为你不应该太担心,除非你做的事非常具体,或者至少在出现实际的性能问题之前。现在还是时候改变哈希算法,没有其他影响。
答案 1 :(得分:0)
主要问题是您需要尽可能减少不同键的相等哈希值。因此,根据实际值,您可以使用不同的方法(从简单的xor开始到使用CRC)。
因此关键因素是: - 价值范围 - 典型的价值观 - 地图中的元素数量
如果您使用“简单”方法:请务必实际检查地图内容,以确保项目均匀分布在所有不同的存储桶中。
如果您使用“复杂”方法:请务必检查它是否对性能影响不大(通常不是问题。但如果是这样,您可能需要“缓存”哈希值... )