完整哈希函数,用于一组没有更新的整数

时间:2010-11-19 13:26:10

标签: c++ performance hash

在我工作的其中一个应用程序中,必须有这样的函数:

bool IsInList(int iTest)
{
   //Return if iTest appears in a set of numbers.
}

数字列表在应用程序加载时已知(但在同一应用程序的两个实例之间并不总是相同),并且不会在整个程序中更改(或添加)。整数本身可能很大并且范围很大,因此拥有vector<bool>效率不高。性能是一个问题,因为功能处于热点。我听说过 Perfect hashing ,但是找不到任何好的建议。任何指针都会有所帮助。谢谢。

P.S。我理想情况下,如果解决方案不是第三方库,因为我不能在这里使用它们。如果可能的话,那些足以理解和手动实施的东西会很棒。

8 个答案:

答案 0 :(得分:2)

我建议将Bloom Filters与简单的std::map结合使用。

不幸的是,bloom过滤器不是标准库的一部分,所以你必须自己实现它。然而事实证明这是一个非常简单的结构!

Bloom Filter是一个专门解决这个问题的数据结构:这个元素是否是集合的一部分,但这样做的内存要求非常紧张,并且非常快。

轻微的问题是答案是......特殊:这个元素是否是该集合的一部分?

  • 没有
  • 可能(具有取决于布隆过滤器属性的给定概率)

这看起来很奇怪,直到你看一下实现,它可能需要一些调整(有几个属性)来降低概率但是...

对你来说真正有趣的是,对于所有答案的情况,你可以保证它不是该集合的一部分。

因此,Bloom Filter非常适合作为二叉树或哈希映射的门卫。仔细调整它只会让很少的误报通过。例如,gcc uses one

答案 1 :(得分:1)

完美哈希函数将一组输入映射到整数而没有冲突。鉴于您的输入是一组整数,值本身就是一个完美的哈希函数。这与手头的问题无关。

用于测试存在的最明显且易于实现的解决方案是排序列表或平衡二叉树。然后你可以在log(N)时间内决定是否存在。我怀疑它会比那更好。

答案 2 :(得分:1)

我想到的是gperf。但是,它基于字符串而不是数字。但是,可以调整部分计算以使用数字作为哈希生成器的输入。

答案 3 :(得分:1)

整数,字符串,无所谓

http://videolectures.net/mit6046jf05_leiserson_lec08/

在介绍之后,在49:38,你将学习如何做到这一点。由于它具有优雅的证据,因此演示了Dot Product散列函数。大多数哈希函数都像伏都教黑魔法。不要在这里浪费时间,找到适合您的数据类型的东西,并提供一些可调整的SEED用于散列。一个好的组合比增长哈希表的方法更好。

@ 54:30教授绘制了完美哈希标准方法的图片。完美的最小哈希超出了本讲座。 (祝你好运!)

这完全取决于你的修改方式。

请记住,他所展示的分析可以通过了解您正在运行的硬件进一步优化。

std :: map你在99.9%的场景中获得了非常好的表现。如果您的热点多次具有相同的iTest,请将地图结果与临时哈希缓存相结合。

Int是可以执行的数据类型之一:

bool hash[UINT_MAX]; // stackoverflow ;)

然后填写。如果你不关心负数,那么它就容易两倍。

答案 4 :(得分:0)

对于这个问题,我会使用二分搜索,假设可以保持数字列表的排序。

维基百科的example implementations应该足够简单,可以翻译成C ++。

答案 5 :(得分:0)

将N个不同的随机分散的整数映射到N个连续的桶(即完美的最小散列)是不必要或不实际的,重要的是确定可接受的比率。要在运行时执行此操作,您可以从配置最差可接受的比率(比如说1到20)开始,然后选择一个比这个比例更好的比例(比如说1到4),然后随机变化(例如,更改使用的素数)快速计算的哈希算法,以查看您可以轻松地满足日益困难的比率。对于最差的可加性,你没有超时,或者你回到速度较慢但可靠的东西(容器或位移列表来解决碰撞)。然后,为每个X%更好地允许一秒或十(可配置),直到你无法在该比率下成功或达到无品脱效率更好的比率....

大家都很清楚,这适用于仅在运行时已知且没有事先知道有用模式的输入,这就是为什么必须在运行时试验或主动派生不同的散列函数的原因。简单地说“整数输入形成一个哈希”是不可接受的,因为当%-ed进入任何合理的数组大小时会发生冲突。但是,你也不需要瞄准一个完美的阵列。还要记住,你可以拥有一个指向打包数组的稀疏指针数组,因此大型对象浪费的内存很少。

答案 6 :(得分:0)

Original Question

使用它一段时间后,我想出了一些哈希函数,这些函数似乎在字符串上运行得相当好,从而产生了一种独特的完美哈希。

假设数组中的值从L到H不等。这产生范围R = H-L + 1。 一般来说它非常大。

然后我将模数运算符从H向下应用到L + 1,寻找一个映射,使它们保持唯一,但范围较小。

在你的情况下,你使用整数。从技术上讲,它们已经散列,但范围很大。

您可以通过应用模数运算符来获得所需的结果。 可能需要先将哈希函数放在它前面。

也可能是你无法为它找到一个完美的哈希值,在这种情况下你的容器类应该有一个后退位置......二进制搜索,或者地图或类似的东西,这样 你可以保证容器在所有情况下都能正常工作。

答案 7 :(得分:0)

一个trie或者一个van Emde Boas树可能是创建一个空间有效的整数集合的更好的选择,查找时间会对数据结构中的对象数量产生不变,假设即使std :: bitset也是如此大。