C ++使用[](int i){return i;}作为unordered_set散列函数的好习惯?

时间:2016-10-18 02:31:42

标签: c++ hash unordered-set

#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编译器使用prime 4027(这是4000之后的第一个素数,4000是unordered_set的大小)作为除数的除数来划分哈希值,并使用余数来确定哪个密钥应该落入,在这种情况下为0。

我在视觉工作室2015上运行了这段代码,只需将4027更改为4096,它也会向我返回4000.像vs一样,使用4000后的第一个幂作为除数。

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

我想将它们存储在哈希表中,以便我可以非常快速地插入和删除这些键。

而且我不想浪费记忆,我不想保留一个4000长的矢量只需几个整数。

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

所以我想我可以使用[](int i){return i;}作为我的哈希函数。只要我知道我的密钥将分配方式(我的密钥可能非常紧凑,如301,303,304,306,308)

但这是一种好习惯吗?我担心这会导致其他编码器出现碰撞问题。

1 个答案:

答案 0 :(得分:4)

  

而且我不想浪费记忆,我不想保留一个4000长的矢量只需几个整数。

哈希表是什么。这是一种针对性能的记忆权衡。如果你想要一个可以为搜索,插入,删除提供O(1)性能的容器,那么价格就是高内存成本。

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

这些事情没有免费的午餐。

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

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

话虽这么说,你总是可以让你的哈希函数对数字执行一些任意的数学运算。添加任意固定常量,进行一些位移,或其他任何你感觉有效的东西。但同样,这不会阻止某人构建最坏情况。因此,如果您的实际代码经常发生冲突,您应该只为此而烦恼,而且无法删除重要内容而无法删除它们。