我遇到了一个断言:HashSet< T> .Contains()是一个O(1)操作。这令我感到惊讶,因为我遇到的每次哈希讨论都提到了碰撞的可能性,可能导致O(n)运行时间。
好奇,我查看了HashSet< T> .Contains以及HashTable.Contains的文档。这两种方法的文档都提出了同样的主张。
当我查看反射器时,HashSet< T> .Contains()使用for循环实现,遍历包含具有相同散列的值的插槽列表。
现在可以肯定的是,那些关于哈希的讨论也提到了一个好的哈希算法可以避免冲突,在这种情况下,查找确实是O(1)。但是我对Big O表示法的理解是它是最糟糕的运行时间,而不是最好的。
O(1)声明是否错误?或者我错过了什么?
答案 0 :(得分:9)
但我对Big O符号的理解是,这是最糟糕的运行时间,而不是最好的。
不幸的是,在描述算法时,Big-O没有“标准”。通常,它用于描述一般或平均情况 - 而不是最坏的情况。
来自Wikipedia:
...此符号现在经常用于分析算法,以描述算法对计算资源的使用:最坏情况或平均情况......
在这种情况下,它描述了一个标准情况,给定适当的散列。如果你有适当的散列,限制行为对于大小N将是恒定的,因此O(1)。
答案 1 :(得分:7)
一般,它是O(1)。
答案 2 :(得分:6)
对于正确实现的哈希表,查找具有amortized恒定的时间复杂度。
实际上,正如您所说,在发生碰撞时,单个查找可以是O(n)。但是,如果执行大量查找,则每个操作的平均时间复杂度是不变的。
引用维基百科:
摊销分析与平均案例绩效的不同之处在于不涉及概率;摊销分析保证每次操作的时间超过最坏情况的表现。
该方法需要知道哪一系列操作是可能的。这种情况最常见于数据结构,其状态在操作之间持续存在。基本思路是最坏情况下的操作可以改变状态,使最坏情况不会再发生很长时间,从而“摊销”其成本。
答案 3 :(得分:5)
不,Big O没有定义“最坏情况”,它定义了一个限制。基于散列的查找(具有良好的散列算法,提供有效的值分布和低冲突率)随着项目数量的增加而向一个恒定值前进(它们永远不会达到或者是恒定值,但这就是它的限制点)。
答案 4 :(得分:2)
我认为这平均意味着O(1)。
答案 5 :(得分:1)
不,Big-O表示法不一定限于最坏情况。通常情况下,您会看到Big-O是针对最佳案例,平均案例和最差案例发布的。只是大多数人倾向于关注最坏情况。除了哈希表的情况,最坏情况很少发生,所以使用平均情况往往更有用。
是的,良好的哈希函数可以降低碰撞的概率。错误的散列函数可能会导致聚类效应(其中不同的值散列到完全相同的值或接近相同的值)。很容易通过实现HashSet
函数来证明GetHashCode
确实可以成为O(n),使得它始终返回相同的值。
在nutshull中,是HashSet
和Dictionary
可以被描述为具有O(1)运行时复杂性,因为重点在于平均情况。
顺便说一句,Big-O也可用于分析摊销的复杂性。分摊复杂性是指一组独立(有时甚至是不同的)操作在组合在一起时的行为,就像它们是一个大操作一样。例如,splay树被称为摊销O(log(n))搜索,插入和删除复杂度,即使每种情况的最坏情况都是O(n),最好的情况是O(1)。 / p>
答案 6 :(得分:0)
我对Big Oh的理解是“最坏情况”通常是指所涉及的元素数量。因此,如果一个函数用10个元素执行O(n),但是O(n平方)有100个或更多(不确定这样的算法实际存在),那么该算法被认为是O(n平方)。
答案 7 :(得分:0)
O(1)并不一定意味着“最坏情况”。对于哈希,人们通常会说“预期”查找时间为O(1),因为哈希冲突的概率很小。
答案 8 :(得分:0)
散列表不仅具有平均情况性能O(1),而且如果散列函数是随机的,则对于任何给定的百分比P <1。 100%,可以获得的性能P%的时间来自正确设计的哈希故事是O(1)。尽管随着N的增加,极端寄生虫病例变得越来越严重,但即使是中度寄生虫病例的可能性也越来越小,这种情况就会得到平衡。