a_c*_*ent 5 java algorithm hashmap time-complexity
我想知道replace(Key , Value)
for a HashMap
is的复杂性是什么。
我最初的想法是O(1)
因为它是O(1)
获取值,我可以简单地替换分配给键的值。
我不确定是否应该考虑在 java 中实现的大型哈希图中可能存在的冲突java.util
。
HashMap#replace
已O(1)
摊销;
并且在地图适当平衡的前提下,Java 在您的put
和remove
调用期间负责,也未摊销。
它是否也适用于非摊销分析取决于有关实施的自平衡机制的问题。
基本上,由于replace
只改变值不影响散列和HashMap中的一般结构,替换值将不会触发任何重新散列或内部结构的重新组织。
因此,我们只支付定位 的成本key
,这取决于桶的大小。
桶大小,如果地图适当地自平衡,可以被认为是一个常数。从而O(1)
为replace
也非摊销。
但是,该实现仅基于启发式因素触发自平衡和重新散列。对此的深入分析有点复杂。
因此,由于启发式方法,现实可能介于两者之间。
可以肯定的是,让我们看看当前的实现(Java 16):
@Override
public V replace(K key, V value) {
Node<K,V> e;
if ((e = getNode(key)) != null) {
V oldValue = e.value;
e.value = value;
afterNodeAccess(e);
return oldValue;
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
该方法afterNodeAccess
是子类的虚拟方法,并且在HashMap
. 除了微不足道的getNode
运行之外的一切O(1)
。
getNode
getNode
是在 a 中定位条目的规范实现HashMap
,我们知道它运行在O(1)
适当的自平衡映射中,例如 Java 实现。让我们来看看代码:
/**
* Implements Map.get and related methods.
*
* @param key the key
* @return the node, or null if none
*/
final Node<K,V> getNode(Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n, hash; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & (hash = hash(key))]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
此方法基本上计算 hash hash = hash(key)
,然后在 中查找 hashtable
first = tab[(n - 1) & (hash = hash(key))]
并开始迭代存储在存储桶中的数据结构。
关于桶的数据结构,我们在if (first instanceof TreeNode)
.
存储桶要么是简单的隐式链表,要么是红黑树。
对于链表,我们有一个简单的迭代
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
Run Code Online (Sandbox Code Playgroud)
这显然O(m)
与m
链表的大小有关。
对于红黑树,我们有
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
Run Code Online (Sandbox Code Playgroud)
在红黑树中查找是O(log m)
,m
是树的大小。
Javas 实现确保在检测到失控时通过重新散列来重新平衡存储桶(您为每个修改方法(如put
或remove
)支付费用)。
因此,在这两种情况下,我们都可以将桶的大小视为常数,或者由于涉及自平衡的启发式方法,接近常数。
具有固定大小的水桶,有效,使得getNode
运行O(1)
,导致replace
在运行O(1)
也是如此。
如果没有任何自平衡机制,在最坏的情况下,它会降级为O(n)
如果使用链表和O(log n)
红黑树(对于所有键都产生哈希冲突的情况)。
随意深入研究代码,但它在那里变得有点复杂。
归档时间: |
|
查看次数: |
151 次 |
最近记录: |