哈希表运行时复杂度(插入,搜索和删除)


72

为什么我在哈希表上仍然看到这些函数的不同运行时复杂性?

在Wiki上,搜索和删除均为O(n)(我认为哈希表的要点是具有恒定的查找,因此,如果搜索为O(n)的意义是什么)。

在不久前的一些课程笔记中,我看到了许多复杂的情况,具体取决于某些细节,包括一个包含所有O(1)的细节。如果我可以全部获得O(1),为什么还要使用其他实现?

如果我以C ++或Java之类的语言使用标准哈希表,那么我期望的时间复杂度是多少?


一个完美的方法是O(1)查找,但是为此,您必须在设计表时知道数据将是什么。
Mooing Duck 2012年

2
O(n)是最坏的情况,O(1)是平均情况。在最坏的情况下,您可能会插入N个全部散列到同一存储桶中的元素。然后,对于此数据集,删除和搜索也将为O(n)。
拉里·渡边2012年

Answers:


143

哈希表O(1) 平均和摊销的情况下的复杂性,但是它遭受O(n) 最坏情况下的时间复杂性的困扰。[我认为这就是您的困惑所在]

O(n)由于两个原因,哈希表的时间复杂度最差:

  1. 如果将太多元素散列到同一个键中:在此键中查找可能会花费一些O(n)时间。
  2. 哈希表通过其负载平衡后-必须重新哈希[创建一个更大的新表,并将每个元素重新插入到该表中]。

但是,这被认为是O(1)平均和摊销的情况,因为:

  1. 很少有很多项目会被散列到相同的键[如果您选择了一个好的散列函数,并且负载平衡不大。
  2. 重新哈希运算O(n)()最多可以在n/2ops之后进行,而ops都是假设的O(1):因此,当您将每个op的平均时间相加时,将得到:(n*O(1) + O(n)) / n) = O(1)

请注意,由于存在重新哈希问题-实时应用程序和需要低延迟的应用程序-不应将哈希表用作其数据结构。

编辑:哈希表的另一个问题:缓存
大型哈希表中性能可能会下降的另一个问题是缓存性能。哈希表的缓存性能很差,因此对于大型集合来说,访问时间可能会更长,因为您需要将表的相关部分从内存重新加载到缓存中。


谢谢-我想我明白了。因此,如果在考试或面试中要求我提供在O(1)中执行查找的数据结构,您是否知道包含哈希表是否可以?
user1136342'2

1
@ user1136342:这取决于您需要最坏情况还是一般情况。对于一般情况,哈希表为O(1)。如果您需要最坏的情况-哈希表是不够的。
amit 2012年

1
维基说最坏的情况下可以减少O(n)O(log n)通过使用每个桶中的更复杂的数据结构。(我猜想如果哈希表已经在使用一个好的加密哈希,这可能会被认为是过大的,即使在攻击者的攻击下,它也可以防止冲突。)
joeytwiddle

@joeytwiddle将排序后的数组作为辅助数据结构并不难,因此您确实可以保证查找O(log(n))最坏的情况。还有其他哈希表可以保证O(log(n))最坏情况的查找,例如哈希排序,并且通过使用大小为n²的完美哈希表作为辅助数据结构,甚至可以保证O(1)最坏情况的查找。
Wolfgang Brehm,

抱歉,不是全部,但是某些哈希表在查找时的最坏情况范围比O(n)更严格。也许您可以这样写:“大多数散列表的实现由于两个原因而遭受O(n)最坏的时间复杂性的困扰:”
Wolfgang Brehm,

19

理想情况下,哈希表为O(1)。问题在于两个键是否相等,但是它们导致相同的哈希。

例如,假设字符串“这是最好的时间,这是最坏的时间”“ Green Eggs and Ham”(绿色鸡蛋和火腿)的哈希值均为123

插入第一个字符串后,将其放在存储区123中。插入第二个字符串时,将看到bucket的值已存在123。然后,它将新值与现有值进行比较,然后发现它们不相等。在这种情况下,将为该键创建一个数组或链接列表。在这一点上,O(n)随着哈希表需要遍历该存储桶中的每个值以找到所需的值,检索该值变得很重要。

因此,在使用哈希表时,重要的是使用具有真正好的哈希函数的键,该键既快速又不会经常导致不同对象的值重复。

说得通?


as the hashtable needs to iterate through each value in that bucket但是存储桶不包含n项目,仅包含散列到该特定键的项目?
SamAko

1
注意:可以使用平衡树来代替链表,以实现lg(n)检索,就像Java 8+一样。
EntangledLoops

2
@ T.Rex:在最坏的情况下,存储桶中会有n物品
jose


7

也许您在看空间的复杂性?那就是O(n)。其他复杂性是哈希表条目上预期的。随着存储桶数量的增加,搜索复杂度接近O(1)。如果在最坏的情况下,哈希表中只有一个存储桶,则搜索复杂度为O(n)。

编辑以回应评论 我认为O(1)是平均情况是不正确的。确实是(如Wikipedia页面所说)O(1 + n / k),其中K是哈希表的大小。如果K足够大,则结果有效为O(1)。但是假设K为10,N为100。在这种情况下,每个存储桶平均要有10个条目,因此搜索时间肯定不是O(1);它是最多10个条目的线性搜索。


哦,我只是在看最坏的情况。因此要明确一点,当人们说O(1)时,它们仅表示平均情况?
user1136342'2

@ user1136342:编辑了答案以试图阐明这一点。
Mark Wilkins'2

2
通常,哈希表的负载平衡table_size/8 <= #elements <= table_size/2,因此返回到O(1)。但是,如果表的大小是动态的-仍然存在重新哈希问题,这同样是最糟糕的情况O(n)。查看我的答案以获取详细信息和解释。
amit 2012年

3

取决于实现哈希的方式,在最坏的情况下,它可以变为O(n),在最佳情况下,它可以变为0(1)(通常,如果您的DS不那么大,则可以实现)


如果可以实现它使其成为O(1),为什么还要实现它使其成为O(n)?
user1136342'2

好吧,我说的是最坏的情况
jmj 2012年

@JigarJoshi:您能否列举最坏的例子来获取O(n)运行时间?
雷切尔2012年

2
返回单个数字的哈希函数,因此所有条目都在同一个存储桶中
jmj 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.