c++使用[](int i){return i;}作为unordered_set散列函数

C++ is using [](int i){return i;} as unordered_set hash fuction good practice?

本文关键字:作为 unordered 散列函数 set return 使用 int c++      更新时间:2023-10-16
#include <iostream>
#include <unordered_set>
using namespace std;
int main() 
{
    auto hash = [](int i) {return i; };
    unordered_set<int, decltype(hash)> s(4000, hash);
    for (int i = 0; i < 4000; i++)
        s.emplace(i * 4027);
    cout<<s.bucket_size(0)<<endl;//4000 here ,all the keys fell into the same bucket .
    return 0;
}
http://ideone.com/U1Vs1P

我发现ideone编译器使用素数4027(这是4000之后的第一个素数,4000是unordered_set的大小)作为除数来除哈希值,并使用余数来确定键应该落在哪个桶中,在这种情况下是0。

我在visual studio 2015上运行这段代码,只是将4027更改为4096,它也返回4000给我。似乎vs使用4000后2的第一次幂作为除数。

我的问题是,我有几个唯一的整数(可能是数百个),它们都在[0,4000]区间内。

我想把它们存储在哈希表中,这样我就可以快速地插入和删除这些键。

我不想浪费内存,我不想为几个int值保留一个4000长的vector

我尝试了默认的unordered_set,但是它的哈希函数太慢了。

所以我认为我可以使用[](int I){return I;}作为我的哈希函数。只要我知道我的键将以这种方式分布(我的键可能非常紧凑,如301,303,304,306,308)。

我不想浪费内存,我不想为几个int值保留一个4000长的vector

哈希表就是这样的。这是一种内存换性能的权衡。如果您想要一个可以为搜索、插入、删除提供0(1)性能的容器,那么代价是高昂的内存成本。

基于节点的set具有较低的内存成本,但有O(log(n))次搜索操作和大量动态分配,但插入和删除相对较快(忽略搜索时间)。基于数组的flat_set(又名:排序的vector)给你尽可能小的内存(以及非常快的从开始到结束迭代),但是O(log(n))的搜索和插入/删除操作对于大集合来说可能非常慢。

天下没有免费的午餐。

处理这类事情的唯一方法是确保桶的数量相对于元素的数量足够大。这将有助于减少碰撞。

如果你知道哈希表的实现和你使用的哈希函数,你可以总是构造一系列代表最坏情况的数字。但是哈希表并不是为最坏情况而优化的;它们针对一般情况进行了优化,即大多数元素不会碰撞。

也就是说,你总是可以让你的哈希函数对数字执行一些任意的数学运算。添加一个任意的固定常数,做一些位移,或者任何你觉得有效的方法。但是,这并不能阻止人们构建最坏的情况。因此,只有当你的实际代码经常发生冲突,并且你不能在不删除重要内容的情况下消除它们时,你才应该麻烦这样做。