C语言中的布谷鸟散列

C语言中的布谷鸟散列,c,hashtable,C,Hashtable,有人在C中实现了吗?如果有一个开源的,非GPL版本,它将是完美的 既然亚当在他的评论中提到了它,有人知道为什么它没有被广泛使用吗?这仅仅是一个实现的问题,还是良好的理论属性没有在实践中具体化?布谷鸟哈希在学术界之外相对未被使用(除了硬件缓存之外,硬件缓存有时借鉴了硬件缓存的思想,但实际上并没有完全实现)。它需要一个非常稀疏的哈希表来获得良好的插入时间——为了获得良好的性能,您确实需要有51%的表是空的。因此,它要么速度快,占用大量空间,要么速度慢,有效利用空间——决不能两者兼而有之。其他算法既节

有人在C中实现了吗?如果有一个开源的,非GPL版本,它将是完美的


既然亚当在他的评论中提到了它,有人知道为什么它没有被广泛使用吗?这仅仅是一个实现的问题,还是良好的理论属性没有在实践中具体化?

布谷鸟哈希在学术界之外相对未被使用(除了硬件缓存之外,硬件缓存有时借鉴了硬件缓存的思想,但实际上并没有完全实现)。它需要一个非常稀疏的哈希表来获得良好的插入时间——为了获得良好的性能,您确实需要有51%的表是空的。因此,它要么速度快,占用大量空间,要么速度慢,有效利用空间——决不能两者兼而有之。其他算法既节省时间又节省空间,尽管只考虑时间或空间时,它们比布谷鸟算法差

这是一本书。检查生成器的许可证,以验证输出是否为非GPL。应该是的,但还是要检查一下


-Adam

IO语言有一个,在PHash.c中。您可以在Github上找到。IO是BSD许可的。

我明白利用率的要点,但这就是我尝试这种特定哈希方案的理由。如果我错过了什么,请告诉我

据我所知,创建动态字典的哈希表的可能替代方法是(平衡的)二叉树和SkipList。为了便于讨论,让我们从键和值类型中抽象出来,假设我们将通过
void*
访问值

对于二叉树,我会:

struct node {
  void *key;
  void *value;
  struct node *left;
  struct node *right;
}
struct slot {
  void *key;
  void *value;
}
因此,假设指针的大小都是s,要存储n个项目,我需要4个s字节

SkipList几乎等同于节点中指针的平均数量为2

在哈希表中,我会:

struct node {
  void *key;
  void *value;
  struct node *left;
  struct node *right;
}
struct slot {
  void *key;
  void *value;
}
因此,每个项目只需要存储2 s字节。如果加载系数为50%,要存储n个项目,我将需要与树相同的4s字节

这对我来说似乎并不太糟糕:布谷鸟哈希表将占用与二叉树大致相同的内存量,但会给我O(1)访问时间,而不是O(logn)

不计算保持树平衡的复杂性以及在节点中存储平衡信息可能需要的其他信息

其他哈希方案可以实现更好的负载因子(比如75%或80%),而不保证最坏情况下的访问时间(甚至可能是O(n))

顺便说一下,和“”似乎能够在保持恒定访问时间的同时增加负载系数

布谷鸟哈希对我来说似乎是一种很有价值的技术,我认为它已经被探索过了;这就是我问题的原因

在“一个接一个”的评论之后,我已经实现并测试了几个版本的布谷鸟哈希,以确定真正的内存需求

经过一些实验后,声称在桌子几乎满了50%之前不必重新翻动的说法似乎是正确的,特别是如果实施了“”技巧

问题是当你放大桌子的时候。通常的方法是将其大小加倍,但这导致新表的利用率仅为25%

事实上,假设hashtable有16个插槽,当我插入第8个元素号时,好的插槽将用完,必须重新刷新。我会加倍,现在的表是32个插槽,其中只有8个被占用,这是一个75%的浪费

这是获得“恒定”检索时间的代价(就访问/比较次数上限而言)

不过,我设计了一个不同的模式:从2的幂大于1开始,如果表有n个插槽,且n是2的幂,则添加n/2个插槽,否则添加n/3个插槽:

+--+--+
|  |  |                             2 slots
+--+--+

+--+--+--+
|  |  |  |                          3 slots
+--+--+--+ 

+--+--+--+--+
|  |  |  |  |                       4 slots
+--+--+--+--+

+--+--+--+--+--+--+
|  |  |  |  |  |  |                 6 slots
+--+--+--+--+--+--+

+--+--+--+--+--+--+--+--+
|  |  |  |  |  |  |  |  |           8 slots
+--+--+--+--+--+--+--+--+
等等

再加上假设只有在表满50%时才进行重新清灰,这导致了这样一个事实,即重新清灰(即最坏情况)后,表将只有66%为空(1/3),而不是75%为空(1/4)

我还计算出(但我仍然需要检查数学)每次放大sqrt(n),浪费的空间逐渐接近50%

当然,为减少内存消耗而付出的代价是最终需要的研究次数的增加。唉,没有什么是免费的

如果有人感兴趣,我将进一步调查。


HTH

正如其他答案所指出的,最简单的布谷鸟哈希表确实要求该表为半空。然而,这一概念已被推广到d元布谷鸟散列,其中每个密钥都有d个可能的嵌套位置,而在简单版本中只有2个


可接受的负载系数随着d的增加而迅速增加。仅对于d=3,您就可以使用大约75%的满表。缺点是需要d个独立的散列函数。为此,我非常喜欢Bob Jenkins的哈希函数(请参阅),您可能会发现它在布谷鸟哈希实现中很有用。

我不能说是软件,但布谷鸟哈希肯定会在硬件中使用,并且变得非常流行。网络设备的主要供应商一直在研究布谷鸟哈希法,有些已经在使用它了。布谷鸟哈希的吸引力当然来自于恒定的查找时间,但也来自于近乎恒定的插入时间

虽然插入理论上可以是无界的,但实际上它可以限定为表中行数的O(logn),并且当测量时,插入时间平均约为1.1*d个内存访问。这只比绝对最小值多10%!内存访问通常是网络设备的限制因素


独立的散列函数是必须的,正确选择它们很困难。祝你好运。

尽管这是一个老问题,但可能仍有人感兴趣:)

描述在GPU(CUDA/OpenCL)上并行d元布谷鸟哈希的实现。它的描述非常好,并且基于描述实现它非常容易。如果你对这个话题感兴趣,通常值得一读