【问题标题】:C++ : Writing a custom hash function for unordered_set that uses the number of buckets in the hash tableC++:为 unordered_set 编写一个自定义散列函数,它使用散列表中的桶数
【发布时间】:2016-07-21 11:38:27
【问题描述】:

我正在为类 Coord(二维坐标)编写自定义散列函数。

是否可以更改以下哈希函数,使 b 为 unordered_set 哈希表中的当前桶数,并在桶数改变时更改?

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::cbrt(b)pow(b,(1.0/3.0) 更准确、更快。更具可读性

标签: c++ hash unordered-set


【解决方案1】:

我认为这不是一个好主意,因为如果哈希表增长,您的所有哈希都会改变,影响现有元素。只需返回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);
  }
};

【讨论】:

  • 我一直在使用这种方法,但担心如果负载因子迫使桶数增加,哈希函数的效率会降低。我可以通过最初分配大量存储桶来解决这个问题,但想知道是否有更好、更便携的选择。
  • 与您自己的模数版本相比,它的效率不会降低,因为随着表的增长,桶数会发生变化,并且会重新计算哈希值。
  • 但是由于哈希函数独立于桶数,如果表增长,哈希的结果肯定不会改变......这不会限制前 b 个桶的值,即使在之后重提一遍,让增长表毫无意义?
【解决方案2】:

唯一可移植且有效的方法是计算尽可能均匀分布在 std::size_t 范围内的哈希值。对于给定的键,哈希函数在程序执行期间返回相同的哈希码很重要。

随着无序映射的增长,它会自行重新散列。由于键是不可变的,因此无法将新的存储桶计数传达给键以计算新的哈希值(在任何情况下都会在映射中取模)。

更进一步:

寻求将存储桶计数传达给键(例如,通过引用或可变数据成员)只会以泪水告终,而且会是一个错误。

一个问题是这会将这个键类与地图类耦合——这已经够糟糕了,但是......

更糟糕的是,无序地图不会与您通信以警告您它即将重新散列。您必须在插入项目后发现这一点。这意味着地图中的所有项目现在都具有基于旧存储桶计数的哈希值。尝试在地图中插入副本很可能会成功,这会破坏地图的语义!

要使这项工作正常进行,每次插入后,您必须将所有项目删除到向量中,重新计算它们的哈希值,然后重新插入它们。

太可怕了!!!

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

【讨论】:

  • 我理解你的观点,所以会避免这样做。但是,您能否澄清一下 rehash 是如何进行的?如果哈希表增长,b 现在小于桶数的事实是否会继续限制前 b 个桶的值?
  • 重做您的哈希函数,使其产生从 std::size 的 0 到最大值的或多或少均匀分布的哈希码。地图会处理剩下的事情。
  • 完美,谢谢!我没有意识到 b 的值可能大于桶的数量。该程序现在按预期运行。
猜你喜欢
  • 2021-12-24
  • 2020-08-20
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 2013-09-09
  • 1970-01-01
  • 2021-02-18
  • 1970-01-01
相关资源
最近更新 更多