为什么通过键O(1)访问字典的元素,即使哈希函数可能不是O(1)?

时间:2016-05-20 13:50:43

标签: c# dictionary hashtable big-o

我知道你如何通过密钥访问你的收藏。但是,哈希函数本身在幕后有很多操作,不是吗?

假设你有一个非常有效的哈希函数,它仍然可能需要很多操作。

可以解释一下吗?

8 个答案:

答案 0 :(得分:130)

O(1)并不意味着即时。 O(1)表示常量,而不考虑数据的大小。哈希函数需要一定的时间,但该时间量不会随着集合的大小而缩放。

答案 1 :(得分:112)

  

HashFunc本身在幕后有很多操作

这当然是对的。但是,这些操作的数量取决于的大小,而不是插入密钥的哈希表的大小:要计算的操作数哈希函数对于具有十个或一万个条目的表中的键是相同的。

这就是为什么哈希函数的调用通常被认为是O(1)。这适用于固定大小的键(整数值和固定长度的字符串)。它还为具有实际上限的可变大小键提供了合适的近似值。

但一般来说,哈希表的访问时间是O(k),其中k是哈希键大小的上限。

答案 2 :(得分:15)

这意味着无论您的收藏大小如何,检索任何会员的时间仍然几乎相同。

所以换句话说,有5个成员的词典会让coud花大约0.002毫秒来访问其中一个,而25个成员的词典应该采取类似的东西。 Big O表示算法复杂度超过集合大小而不是实际的语句或执行的函数

答案 3 :(得分:12)

如果将字典/地图实现为HashMap,则它具有O(1)最佳案例复杂度,因为我最好的情况是它需要完全计算哈希值 - 如果没有关键冲突,则检索关键元素的代码。

如果你有很多关键冲突或非常糟糕的哈希函数, hash-map 可能会有{em>最差情况运行时复杂度 O(n),因为在这种情况下,它会降级为保存数据的整个数组的线性扫描。

此外,O(1)并不意味着立即,这意味着它具有常量金额。因此,为字典选择正确的实现也可能取决于集合中元素的数量,因为如果只有少数条目,那么函数的非常高的常量成本会更糟。

这就是为什么字典/地图针对不同的场景实现不同的原因。对于Java,有多种不同的实现,C ++使用红/黑树等。您可以根据数据的数量并根据它们的最佳/平均/最差情况运行时效率来选择它们。

答案 4 :(得分:6)

理论上它仍然是O(n),因为在最坏的情况下,所有数据都可能最终具有相同的散列并捆绑在一起,在这种情况下,您必须线性地遍历所有数据。

答案 5 :(得分:3)

请参阅帖子What does "O(1) access time" mean?

散列函数中的操作数无关紧要,只要它对集合中的每个元素花费相同(恒定)的时间量即可。例如,访问2个元素集合中的一个元素需要0.001毫秒,但访问2,000,000,000个元素集合中的一个元素需要0.001毫秒。虽然哈希函数可以包含数百个if语句和多个计算。

答案 6 :(得分:1)

来自文档:

  

使用其键检索值非常快,接近于O(1),因为T:System.Collections.Generic.Dictionary`2类是作为哈希表实现的。

所以它可以是O(1)但可能更慢。 在这里,您可以找到有关哈希表性能的另一个主题:Hash table - why is it faster than arrays?

答案 7 :(得分:1)

一旦你允许越来越大的字典占用更多内存,进一步降低缓存层次结构并最终减慢磁盘上的交换空间,很难说它确实是O(1)。随着字典变大,字典的性能会变慢,可能会给出O(log N)时间复杂度。不相信我?使用1,100,1000,10000等字典元素自己尝试,最多可以说1000亿,并测量实际查找元素所需的时间。

但是,如果您简化假设系统中的所有内存都是随机存取内存,并且可以在固定时间内访问,那么您可以声称字典是O(1)。这种假设很常见,即使对于任何具有磁盘交换空间的机器来说都不是这样,并且在任何情况下,考虑到各种级别的CPU缓存,这仍然是值得商榷的。