HashMap mise en œuvre en Java. Comment le seau de calcul de l'indice de travail?
Je suis à la recherche à la mise en œuvre de HashMap
en Java et je suis coincé à un moment donné.
Comment est la indexFor
fonction est-elle calculée?
static int indexFor(int h, int length) {
return h & (length-1);
}
Grâce
Vous devez vous connecter pour publier un commentaire.
Ce n'est pas le calcul de la de hachage, c'est le calcul de la seau.
L'expression
h & (length-1)
fait un peu sageAND
surh
à l'aide delength-1
, qui est comme un masque de bits, pour ne retourner que les bits de bas deh
, ce qui rend pour un super-rapide variante deh % length
.length
est une puissance de 2?length -1
à la solde de l'écart entre les seauxLe hachage est lui-même calculé par le
hashCode()
méthode de l'objet que vous essayez de magasin.Ce que vous voyez ici est le calcul de la "seau" pour stocker l'objet basé sur le hachage
h
. Idéalement, pour éviter les collisions, vous avez le même nombre de compartiments comme c'est le maximum réalisable valeur deh
- mais qui pourrait être trop gourmandes en mémoire. Par conséquent, vous ont généralement un faible nombre de compartiments avec un danger de collision.Si
h
est, disons, 1000, mais vous avez seulement 512 seaux dans votre sous-jacente de tableau, vous devez savoir où placer l'objet. Généralement, unmod
opération surh
serait suffisant, mais c'est trop lent. Compte tenu de la propriété interne deHashMap
que le sous-jacent de la matrice de toujours a nombre de compartiments égal à2^n
du Soleil, les ingénieurs ont pu utiliser l'idée deh & (length-1)
, il fait un au niveau du bit ET avec un nombre composé de tous1
's, pratiquement lecture seulement len
plus bas les bits de la table de hachage (qui est le même que le fait de faireh mod 2^n
, seulement beaucoup plus rapide).Exemple:
hashCodes
si le plus bas 9 ou si les bits d'accord, mais les bits supérieurs sont-ils différents?Il est en train de calculer le seau de la table de hachage de la carte où l'entrée (paire clé-valeur) seront stockées. Le seau id est
hashvalue/buckets length
.Un hachage carte se compose de seaux; les objets seront placés dans ces seaux basé sur le seau id.
N'importe quel nombre d'objets peuvent tomber dans le même compartiment basé sur leur
hash code /buckets length
valeur. Cela s'appelle une "collision".Si de nombreux objets de tomber dans le même seau, tandis que la recherche de leur méthode equals() sera appelée pour lever l'ambiguïté.
Le nombre de collisions est indirectement proportionnelle à la segment de longueur.
La réponse ci-dessus est très bonne, mais je tiens à expliquer pourquoi Java peut utiliser
indexFor
pour créer des indexExemple, j'ai un
HashMap
comme ceci (ce test est sur Java7, je vois Java8 changement HashMap beaucoup, mais je pense que cette logique du toujours très bon)Vous pouvez voir l'index de l'entrée avec la touche
"A"
et de l'objet avec les principaux"P"
et de l'objet avec les principaux"r"
ont le même indice (= 5). Et voici le débogage de suite après j'exécute le code ci-dessusTable dans l'image est ici
=> je vois
Si les indices sont différents, une nouvelle entrée sera ajouter à la table
Si l'indice est même et
hash
est même, la nouvelle valeur sera mise à jourSi l'indice est même et
hash
est différents, une nouvelle entrée sera point à l'ancienne entrée (comme unLinkedList
). Alors, vous savez pourquoiMap.Entry
ont champnext
Vous pouvez vérifier à nouveau par lire le code dans
HashMap
.Comme maintenant, vous pouvez penser que
HashMap
sera jamais besoin de changer la taille (16) parce queindexFor()
toujours valeur de retour <= 15 mais il pas correcte.Si vous regardez
HashMap
codeHashMap
redimensionner le tableau (le double de la longueur de la table) lorsquesize
>=threadhold
Qu'est-ce que
threadhold
?threadhold
est calculé ci-dessousQuel est le
size
?size
est calculé ci-dessous.Bien sûr,
size
ici n'est pastable.length
.Tout le temps de vous mettre une nouvelle entrée
HashMap
etHashMap
besoin de créer une nouvelle entrée (à noter queHashMap
de ne pas créer une nouvelle entrée lorsque la clé est la même, il vient de remplacer la valeur pour existaient entrée) puissize++
Espoir aide
bucket_index = (j'.hashCode() && 0x7FFFFFFFF) % hashmap_size fait le tour