关于c#:关于时间和空间哪个最好:Bloom过滤器,哈希表或字典?


Which is best regarding the time and space: Bloom filter, Hash table or Dictionary?

我需要用C_存储4000个固定大小(8字符)的字符串,但我不知道关于添加和检索项的空间和时间,最好使用什么:bloom过滤器、哈希表或字典?有人能帮我吗


在这个问题中,由于C中的字典是使用哈希表实现的,所以在C中实际上只有两个数据结构。所以我们将字典和哈希表都称为哈希表。如果您使用其中一个,那么您可能需要字典,因为这里介绍的类型安全性和性能:为什么字典比哈希表更受欢迎?但是,由于字典是使用哈希表实现的,所以这两种方法都没有很大的区别。

但真正的问题是哈希表(字典)和Bloom过滤器。以前有人问过相关问题,使用布卢姆过滤器有什么好处?他们还链接到bloom过滤器的维基百科页面,这是非常有用的:https://en.wikipedia.org/wiki/bloom_filter答案的简短版本是bloom过滤器更小更快。然而,它们确实有与此相关的成本:它们并不完全准确。在哈希表中,始终存储原始字符串以进行精确比较。首先散列值,这会告诉您表中要查找的位置。在表中查找完之后,您将对照正在搜索的值检查位于表中的值。在Bloom过滤器中,使用多个散列计算一组位置。如果在所有这些位置都有1,那么考虑找到字符串。这意味着有时会"找到"最初未插入的字符串。如果表太小,事实上,您可以达到饱和点,在那里您尝试的任何字符串都将出现在Bloom过滤器中。因为您知道要插入多少字符串,所以可以适当地调整表的大小以避免这种情况。

让我们看看涉及的尺寸。为了让数字清晰地显示出来,我将假装您正好有4096个字符串。为了使哈希表的冲突相对较低,您希望您的表至少与字符串的数量一样大。因此,实际上(假设为32位(4字节)指针),在本例中,您将看到表的大小为4096*4字节=16K,列表节点(下一个指针+字符串指针)和字符串的大小为4096*(4+4+8)=64K。所以,总的来说,大概是80K左右,在大多数情况下,在使用C_的情况下,这可能不是很大的内存。

对于布卢姆过滤器,我们必须在尺寸计算中确定我们想要达到的误差率。当我们讨论1%的错误率时,这意味着在每100个未插入Bloom过滤器的字符串中,会有1个错误地表示存在。插入的字符串将始终正确地指示为已插入。利用公式m=-n*ln(p)/(ln(2)^2),我们可以计算出最小尺寸,从而得出一定的误差率。在这个方程中,m是表中的槽数,p是错误率,n是要插入的字符串数。所以,如果我们将p设置为0.01(1%的错误),那么我们得到大约9.6*4096位=9.6*512字节=4.8K,这显然要小一些。但是,事实上,1%的错误率有点高。因此,更实际地说,我们应该选择更像0.0001%的值,得出28.8*4096b位=28.8*512字节=14.4K。显然,这两个值都大大小于我们为哈希表计算的80K。但是,哈希表的错误率为0,明显小于1%或0.0001%。

所以,真的,这取决于你是否,在你的情况下,为了获得一点速度和一点时间而失去一些准确度的权衡是值得的。实际上,任何一种选择都可能足够小,足够快,足以应付绝大多数现实世界的情况。


字典是一种抽象数据类型,表示从一种类型到另一种类型的映射。它没有指定字典的实现是什么——它可以由哈希表、平衡二进制搜索树、跳过列表或许多其他结构中的一个来支持。这里可能不合适,因为字典将一种类型的元素与另一种类型相关联。你没有这样做-你只关心存储元素-所以这可能是不适当的。

布卢姆滤波器是一种概率数据结构,它可以很好地检查一个元素是否确实不在集合中,但不能确切地告诉您某个元素是否在集合中。它通常用于分布式系统,以避免不必要的网络读取。每台计算机都可以存储一个bloom过滤器来过滤数据库中可能存在的条目,如果某个条目被过滤器排除,则可以通过不查询远程系统来过滤掉明显不必要的网络调用。这对你想做的事情不是很好,因为误报可能会破坏交易。

不过,哈希表是一个很好的数据结构,可以满足您的需要。它支持元素的快速查找和插入,并且通过良好的实现,可以非常节省内存。但是,它不按排序顺序存储元素,这可能是一个问题,具体取决于您的应用程序。

如果确实需要排序顺序,还有两个可能需要考虑的结构。首先是一个平衡的二进制搜索树,它支持快速查找和删除,并按排序顺序存储元素。有许多好的实现;实际上所有好的编程语言都附带一个实现。另一个是trie,它支持非常快速的查找和访问,并保持排序顺序。根据字符串的分布,它可能有点空间效率低下,但可能正是您要查找的内容。

希望这有帮助!


.NET 1.0中的System.Collections.Hashtable实际上与.NET 2.0中引入的System.Collections.Generic.Dictionary完全相同。

我建议您使用字典,因为它是类型安全的,通过指定您的键和值类型。哈希表只接受对象类型,每次检索数据时都必须将其转换回字符串。