对于只读,无序的唯一字符串集合,性能最快的选项是什么?

时间:2010-06-17 16:21:02

标签: .net performance data-structures string hashset

免责声明:我意识到这个问题的完全明显的答案是HashSet<string>。它非常快,无序,价值独特。

但我只是想知道,因为HashSet<T>是一个可变类,所以它有AddRemove等等。因此,我不确定使这些操作成为可能的基础数据结构是否会在读取操作时牺牲某些性能 - 特别是,我关注Contains。< / p>

基本上,我想知道现有的绝对最快执行数据结构是什么,它可以为Contains类型的对象提供string方法。在.NET框架内部或外部。

我对各种答案感兴趣,不论其局限性如何。例如,我可以想象某些结构可能被限制为一定长度的字符串,或者可能根据问题域(例如,可能的输入值的范围)等进行优化。如果存在,我想听听它。

最后一件事:我不是将其限制为只读数据结构。显然,任何读写数据结构都可以嵌入到只读包装器中。我甚至提到“只读”这个词的唯一原因是我对数据结构没有任何要求以允许添加,删除等。如果它具有这些功能,但是,我不会抱怨。


更新

Moron's answer是我正在寻找的那种事情的一个很好的例子。由于以下原因,Trie *看起来确实是一个很好的可能性HashSet<T>.Contains取决于某些GetHashCode的{​​{1}}函数,IEqualityComparer<string> {3}},在.NET中默认为O(n)**。换句话说,必须检查字符串中的每个字符HashSet<string>.Contains才能返回 true false 。对于Trie,只有true的返回值才需要O(n)来确定;返回值false可能会更快地返回。

这当然是假设的。到目前为止,我还没有编写或遇到过.NET中的Trie实现,它可以在HashSet<string>击败Contains(尽管我自己编写的实现非常接近字母'a'到'z' )。我只是说,似乎有可能。

*顺便提一下,这个链接也让我有了另一个有趣/类似的可能性:as far as I can tell
**这里“n”指的是字符串的长度。

4 个答案:

答案 0 :(得分:2)

Tries适合做Contains,特别是对于有限字母表中的字符串。给定一个字符串s,trie上Contains的时间复杂度为O(| s |)(| s | = s的长度),这是最优的。

答案 1 :(得分:1)

除了你想知道的Hashset是最快的收藏。

没有更快的方法,因为底层的Hashtable允许O(1)读写访问

答案 2 :(得分:1)

哈希容器接近O(1)进行插入和检索,因此从数量级的角度来看,你不可能比这更好。

在哈希容器中,随着时间的推移,您的性能将与两件事相关:哈希函数提供的分布有多好,以及它可以多快地计算它。这些不是等价的 - 分布不佳的函数(最终会导致大量冲突)比速度更慢但分布更好的散列函数更能影响性能。

因此,如果你能想出一个非常快速计算的完美哈希函数,那将是一个改进。以特定方式约束数据可能会使这更容易。但是,不管你想出什么都不会像现有的那样好。

答案 3 :(得分:1)

哈希表分摊O(1)进行查找。不能做得更好,O(1 / n)算法是永动设备。只有两件事使他们表现不佳:

  • 较差的散列函数会导致许多碰撞。最糟糕的一个会将查找退化为O(n)。你可以毫不费力地使用字符串,它们非常好。 String.GetHashCode()做得非常好。
  • 一个大量变异的集合,其中包含许多已提前添加的已删除项目。这可能导致迭代器需要跳过许多空的哈希桶。 O(n)的降解在技术上是可能的,尽管非常罕见。一个简单的解决方法是通过重新分配引用来重建集合(如table = new HashSet(table);)

这类问题很少见。您没有预先设计它们(除了哈希函数),只有在检测到程序的性能问题时才开始考虑它们。