C++:为unordered_set编写一个自定义哈希函数,该函数使用哈希表中的桶数

C++ : Writing a custom hash function for unordered_set that uses the number of buckets in the hash table

本文关键字:函数 哈希 哈希表 自定义 一个 set unordered C++      更新时间:2023-10-16

我正在为类Coord(二维坐标)编写一个自定义哈希函数。

是否可以更改下面的哈希函数,使b是Undered_set哈希表中当前的bucket数量,并且如果bucket数量发生更改,则会更改?

namespace std
{
    template <>
    struct hash<Coord>
    {
        size_t operator()(const Coord &k) const
        {
            int b = 11;
            int a1 = static_cast<int> (pow(b,(1.0/3.0)));
            int a2 = static_cast<int> (pow(b,(2.0/3.0)));
            return ((a1*k.getX() + a2*k.getY()) % b);
        }
    };
}

唯一可移植且有效的方法是计算在std::size_t范围内尽可能均匀分布的哈希。对于给定的密钥,散列函数在程序的持续时间内返回相同的散列代码是很重要的。

随着无序映射的增长,它将重新散列自己。由于密钥是不可变的,因此不可能将新的bucket计数传递给密钥以计算新的散列(在任何情况下,散列都将在映射中进行模运算)。

更进一步:

试图将bucket计数传递给键(例如,通过引用或可变数据成员)只会以撕裂告终,这将是一个错误。

一个问题是,这会将这个键类与map类耦合——这已经够糟糕的了,但是。。。

更糟糕的是,无序映射不会与您通信,以警告您它将要重新散列。你必须在插入项目后发现这一点。这意味着地图中的所有项目现在都有基于旧bucket计数的哈希。尝试在映射中插入重复项很可能会起作用,破坏映射的语义!

要做到这一点,每次插入后,你必须将所有项目删除到一个向量中,重新计算它们的哈希值,然后重新插入它们。

恐怖!!!

请告诉我,我已经说服你不要走这条末日之路。

我认为这不是一个好主意,因为如果哈希表增长,所有的哈希都会改变,影响现有元素。只需返回a1*k.getX() + a2*k.getY(),哈希表实现将为您完成必要的模部分。

也就是说,你可以通过std::unordered_map::bucket_count()获得桶的数量,并将其存储在你的哈希对象中(只是为了说明,不要这样做):

struct MyHash {
  std::size_t bucket_count;
  size_t operator()(const Coord &k) const {
    int a1 = static_cast<int> (pow(b,(1.0/3.0)));
    int a2 = static_cast<int> (pow(b,(2.0/3.0)));
    return ((a1*k.getX() + a2*k.getY()) % bucket_count);
  }
};