为啥HashMap的运算复杂度没有考虑hash函数的复杂度? [复制]
Posted
技术标签:
【中文标题】为啥HashMap的运算复杂度没有考虑hash函数的复杂度? [复制]【英文标题】:Why is the complexity of the hash function not considered in the complexity of HashMap's operations? [duplicate]为什么HashMap的运算复杂度没有考虑hash函数的复杂度? [复制] 【发布时间】:2018-06-21 03:58:33 【问题描述】:对于HashMap<String, String> map
,每次将键值对插入映射时都会计算哈希值 -
java.lang.String#hashCode
public int hashCode()
int h = hash;
if (h == 0 && value.length > 0)
char val[] = value;
for (int i = 0; i < value.length; i++)
h = 31 * h + val[i];
hash = h;
return h;
因为不言自明,put操作的复杂度基本上就是hash计算的复杂度。
那么,为 put/get 操作定义 hashmap 最坏情况时间复杂度的适当方法应该是什么?
如果您从哈希冲突的角度有同样的问题,您可以在这里找到答案: Is a Java hashmap really O(1)?
【问题讨论】:
该代码无法编译(hash
来自哪里?)。另外,究竟您的编程问题/您遇到的问题是什么?
@Todd 这不是重复的 - 这个问题指的是不同的东西。
@FrankSchmitt 该代码是从字符串源中提取的 - hash
是字符串的缓存哈希值。真正的存储,一些字符串(如“polygenelubricants”,将哈希为 0 导致每次调用 hashCode()
时都会计算它们!!
@ravi 这不是同一个问题。请再看一遍
但我认为这里其实有这个问题的答案:***.com/questions/2771368/…
【参考方案1】:
当您计算时间复杂度作为N
的函数时,您必须首先确定N
代表什么。当我们谈论HashMap
操作的复杂性时,N
代表HashMap
的大小(即HashMap
中存储的键值对的数量)。
给定键的hashCode()
的时间复杂度不取决于HashMap
中的条目数。因此,计算hashCode()
需要O(1)
时间(假设您的示例中String
键的长度不是Map
大小的函数-我们可以构造一个奇怪的HashMap<String,String>
,其中@放在Map
中的 987654334@th 键具有 i
字符 - 在这种边缘情况下,hashCode()
计算将花费 O(N)
时间,因此,所有 HashMap
操作将需要 O(N)
时间O(1)
)。
计算hashCode()
后,需要O(1)
时间来确定该键是否已存在于Map
中(因为HashMap
的每个桶中的平均条目数受常数)。
【讨论】:
你能澄清一下“因为HashMap的每个bucket中的平均条目数是由一个常量绑定的”吗? @bonnal-enzoHashMap
有一个负载因子,通常HashMap 有 1000 个桶,它最多有 750 个条目(当您尝试添加第 751 个条目时,桶的数量会增加)。因此,每个桶中的平均条目数
非常清楚,谢谢,您知道达到阈值时桶的数量通常乘以哪个因子? 2?
@bonnal-enzo 是的。桶数是 2 的幂,在 HashMap 调整大小时乘以 2。【参考方案2】:
大 O 表示法是在谈论操作的复杂性。当涉及更多元素时,大多数操作会变得更复杂(即需要更多时间),并且符号描述了复杂性如何相对于元素数量增长。
使用 O(1),您是说操作与所涉及的元素数量无关。由于其自身原因,散列操作可能快或慢,但无论您有 1 个元素的 HashMap 还是它们的 googolplex,该速度都不会改变。
需要注意的是,O(1) 是摊销平均值,不能保证。最坏的情况被认为是 O(n),假设是一个每次返回相同哈希的哈希函数,但可以想象(如 cmets 中的 user889742 所建议的那样)有一个故意坏的哈希码函数,其性能甚至比那个。
【讨论】:
完全有可能每个元素的大小与元素的总数有关。 (例如,序列号,随着元素数量的增长需要更多的数字。)在这种情况下,这个哈希函数会随着元素数量的增长而变慢。 您是绝对正确的,某些哈希码实现可能会导致 HashMap 在插入时不具有 O(1) 复杂度,O(1) 是假定良好哈希码实现的平均值。最坏情况通常被认为是 O(n),其中所有哈希值都相同。我不确定是否考虑过故意使用错误的哈希码;执行无限循环的性能很差。【参考方案3】:您必须知道(1)
的用途。这是数组中元素的数量。插入 HashMap 的成本不会根据映射中的元素数量而改变(假设您已在结构的整个生命周期内分摊了插入成本。)
您正确计算 String
的 hashCode 是 O(n)
其中 n
是字符串的长度。但是,一旦拥有它,无论您使用多少次,它都将永远拥有。所以它的成本被认为是恒定的。
【讨论】:
以上是关于为啥HashMap的运算复杂度没有考虑hash函数的复杂度? [复制]的主要内容,如果未能解决你的问题,请参考以下文章