简体   繁体   English

Java HashMap中的冲突解决方案

[英]Collision resolution in Java HashMap

Java HashMap uses put method to insert the K/V pair in HashMap . Java HashMap使用put方法在HashMap插入K / V对。 Lets say I have used put method and now HashMap<Integer, Integer> has one entry with key as 10 and value as 17. 假设我使用了put方法,现在HashMap<Integer, Integer>有一个条目, key为10, value 17。

If I insert 10,20 in this HashMap it simply replaces the the previous entry with this entry due to collision because of same key 10. 如果我在这个HashMap插入10,20,由于相同的密钥10,它只是由于碰撞而用此条目替换了前一个条目。

If the key collides HashMap replaces the old K/V pair with the new K/V pair. 如果密钥冲突, HashMap会将旧的K / V对替换为新的K / V对。

So my question is when does the HashMap use Chaining collision resolution technique? 所以我的问题是HashMap何时使用链接冲突解决技术?

Why it did not form a linkedlist with key as 10 and value as 17,20? 为什么它没有形成一个关键linkedlist ,密钥为10,值为17,20?

When you insert the pair (10, 17) and then (10, 20) , there is technically no collision involved. 插入对(10, 17)然后插入(10, 17) (10, 20) ,技术上不会发生碰撞。 You are just replacing the old value with the new value for a given key 10 (since in both cases, 10 is equal to 10 and also the hash code for 10 is always 10). 您只是将旧值替换为给定键10的新值(因为在这两种情况下,10等于10,而10的哈希码始终为10)。

Collision happens when multiple keys hash to the same bucket. 当多个密钥散列到同一个桶时发生冲突。 In that case, you need to make sure that you can distinguish between those keys. 在这种情况下,您需要确保可以区分这些键。 Chaining collision resolution is one of those techniques which is used for this. 链接冲突解决方案是用于此的那些技术之一。

As an example, let's suppose that two strings "abra ka dabra" and "wave my wand" yield hash codes 100 and 200 respectively. 举个例子,我们假设两个字符串"abra ka dabra""wave my wand"产生哈希码100200 Assuming the total array size is 10, both of them end up in the same bucket ( 100 % 10 and 200 % 10 ). 假设总阵列大小为10,则它们最终都在同一个桶中( 100 % 10200 % 10 )。 Chaining ensures that whenever you do map.get( "abra ka dabra" ); 链接确保每当你做map.get( "abra ka dabra" ); , you end up with the correct value associated with the key. ,您最终得到与密钥相关的正确值。 In the case of hash map in Java, this is done by using the equals method. 对于Java中的哈希映射,这是通过使用equals方法完成的。

In a HashMap the key is an object, that contains hashCode() and equals(Object) methods. HashMap ,键是一个对象,它包含hashCode()equals(Object)方法。

When you insert a new entry into the Map, it checks whether the hashCode is already known. 在Map中插入新条目时,它会检查hashCode是否已知。 Then, it will iterate through all objects with this hashcode, and test their equality with .equals() . 然后,它将使用此哈希码迭代所有对象,并使用.equals()测试它们的相等性。 If an equal object is found, the new value replaces the old one. 如果找到相等的对象,则新值将替换旧值。 If not, it will create a new entry in the map. 如果没有,它将在地图中创建一个新条目。

Usually, talking about maps, you use collision when two objects have the same hashCode but they are different. 通常,在谈论地图时,如果两个对象具有相同的hashCode但它们不同,则使用碰撞 They are internally stored in a list. 它们在内部存储在列表中。

It could have formed a linked list, indeed. 事实上,它本可以形成一个链表。 It's just that Map contract requires it to replace the entry: 只是Map合同要求它替换条目:

V put(K key, V value)

Associates the specified value with the specified key in this map (optional operation). 将指定的值与此映射中的指定键相关联(可选操作)。 If the map previously contained a mapping for the key, the old value is replaced by the specified value. 如果映射先前包含键的映射,则旧值将替换为指定的值。 (A map m is said to contain a mapping for a key k if and only if m.containsKey(k) would return true.) (当且仅当m.containsKey(k)返回true时,地图m才包含密钥k的映射。)

http://docs.oracle.com/javase/6/docs/api/java/util/Map.html http://docs.oracle.com/javase/6/docs/api/java/util/Map.html

For a map to store lists of values, it'd need to be a Multimap . 对于存储值列表的地图,它需要是Multimap Here's Google's: http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Multimap.html 这是Google的: http//google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Multimap.html

A collection similar to a Map, but which may associate multiple values with a single key. 类似于Map的集合,但可以将多个值与单个键相关联。 If you call put(K, V) twice, with the same key but different values, the multimap contains mappings from the key to both values. 如果使用相同的键但不同的值调用put(K,V)两次,则multimap包含从键到两个值的映射。

Edit: Collision resolution 编辑:碰撞分辨率

That's a bit different. 那有点不同。 A collision happens when two different keys happen to have the same hash code, or two keys with different hash codes happen to map into the same bucket in the underlying array. 当两个不同的密钥碰巧具有相同的哈希码时发生冲突,或者具有不同哈希码的两个密钥碰巧映射到底层阵列中的相同桶中。

Consider HashMap 's source (bits and pieces removed): 考虑HashMap的源代码(删除了一些部分):

public V put(K key, V value) {
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    // i is the index where we want to insert the new element
    addEntry(hash, key, value, i);
    return null;
}

void addEntry(int hash, K key, V value, int bucketIndex) {
    // take the entry that's already in that bucket
    Entry<K,V> e = table[bucketIndex];
    // and create a new one that points to the old one = linked list
    table[bucketIndex] = new Entry<>(hash, key, value, e);
}

For those who are curious how the Entry class in HashMap comes to behave like a list, it turns out that HashMap defines its own static Entry class which implements Map.Entry . 对于那些好奇HashMapEntry类如何表现得像列表的人,事实证明HashMap定义了自己的静态Entry类,它实现了Map.Entry You can see for yourself by viewing the source code: 您可以通过查看源代码自己查看:

GrepCode for HashMap GrepCode for HashMap

First of all, you have got the concept of hashing a little wrong and it had been rectified by Mr. Sanjay. 首先,你有一个哈希的概念有点错误,并且已经被桑杰先生纠正了。

And yes, Java indeed implement a collision resolution technique. 是的,Java确实实现了冲突解决技术。 When two keys get hashed to a same value (as the internal array used is finite in size and at some point the hashcode() method will return same hash value for two different keys) at this time, a linked list is formed at the bucket location where all the informations are entered as an Map.Entry object that contains a key-value pair. 当两个键被散列到相同的值时(因为内部数组的大小是有限的,并且在某些时候hashcode()方法将返回两个不同键的相同散列值),此时会在存储桶中形成链接列表输入所有信息的位置,作为包含键值对的Map.Entry对象。 Accessing an object via a key will at worst require O(n) if the entry in present in such a lists. 如果在这样的列表中存在条目,则通过密钥访问对象将最坏地需要O(n)。 Comparison between the key you passed with each key in such list will be done by the equals() method. 您通过此类列表中的每个键传递的键之间的比较将通过equals()方法完成。

Although, from Java 8 , the linked lists are replaced with trees (O(log n)) 虽然从Java 8开始,链表被树替换(O(log n))

There is difference between collision and duplication. 碰撞和重复之间存在差异。 Collision means hashcode and bucket is same, but in duplicate, it will be same hashcode,same bucket, but here equals method come in picture. 碰撞意味着hashcode和bucket是相同的,但是一式两份,它将是相同的hashcode,同一个桶,但这里等于方法进入图片。

Collision detected and you can add element on existing key. 检测到碰撞,您可以在现有密钥上添加元素。 but in case of duplication it will replace new value. 但如果重复,它将取代新的价值。

There is no collision in your example. 您的示例中没有冲突。 You use the same key, so the old value gets replaced with the new one. 您使用相同的密钥,因此旧值将替换为新值。 Now, if you used two keys that map to the same hash code, then you'd have a collision. 现在,如果你使用两个映射到相同哈希码的键,那么你就会发生冲突。 But even in that case, HashMap would replace your value! 但即使在这种情况下,HashMap也会取代你的价值! If you want the values to be chained in case of a collision, you have to do it yourself, eg by using a list as a value. 如果您希望在发生冲突时链接值,则必须自己进行,例如使用列表作为值。

It isn't defined to do so. 没有定义这样做。 In order to achieve this functionality, you need to create a map that maps keys to lists of values: 为了实现此功能,您需要创建一个将键映射到值列表的映射:

Map<Foo, List<Bar>> myMap;

Or, you could use the Multimap from google collections / guava libraries 或者,您可以使用google collections / guava库中的Multimap

Your case is not talking about collision resolution, it is simply replacement of older value with a new value for the same key because Java's HashMap can't contain duplicates (ie, multiple values ) for the same key . 你的情况是不是在谈论冲突解决,那简直是与相同的密钥的新值替换旧的价值,因为Java的HashMap不能包含相同的密钥副本(即多个 )。

In your example, the value 17 will be simply replaced with 20 for the same key 10 inside the HashMap. 在您的示例中,对于HashMap内的相同键10,值17将简单地替换为20。

If you are trying to put a different/new value for the same key, it is not the concept of collision resolution, rather it is simply replacing the old value with a new value for the same key. 如果您尝试为同一个键设置不同的/新值,则它不是冲突解决的概念,而只是将旧值替换为相同键的新值。 It is how HashMap has been designed and you can have a look at the below API (emphasis is mine) taken from here . 它是如何HashMap的设计,你可以看看下面的API(重点是我的)取自这里

public V put(K key, V value) 公共V放(K键,V值)

Associates the specified value with the specified key in this map. 将指定的值与此映射中的指定键相关联。 If the map previously contained a mapping for the key, the old value is replaced . 如果映射先前包含键的映射,则替换旧值


On the other hand, collision resolution techniques comes into play only when multiple keys end up with the same hashcode (ie, they fall in the same bucket location) where an entry is already stored. 另一方面,只有当多个密钥以相同的哈希码 (即,它们落在相同的桶位置) 结束时,冲突解决技术才会起作用,其中已经存储了条目。 HashMap handles the collision resolution by using the concept of chaining ie, it stores the values in a linked list (or a balanced tree since Java8, depends on the number of entries). HashMap通过使用链接的概念来处理冲突解决方案,即它将值存储在链表中(或者自Java8以来的平衡树,取决于条目的数量)。

When multiple keys end up in same hash code which is present in same bucket. 当多个密钥最终存在于同一个存储桶中的相同哈希码中时。 When the same key has different values then the old value will be replaced with new value. 当相同的键具有不同的值时,旧值将替换为新值。

Liked list converted to balanced Binary tree from java 8 version on wards in worst case scenario. 在最坏的情况下,喜欢的列表从病房的java 8版本转换为平衡的二进制树。

Collision happen when 2 distinct keys generate the same hashcode() value. 当2个不同的密钥生成相同的hashcode()值时发生冲突。 When there are more collisions then there it will leads to worst performance of hashmap. 当存在更多冲突时,它将导致hashmap的最差性能。

Objects which are are equal according to the equals method must return the same hashCode value. 根据equals方法相等的对象必须返回相同的hashCode值。 When both objects return the same has code then they will be moved into the same bucket. 当两个对象返回相同的代码时,它们将被移动到同一个存储桶中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM