Si les seaux sont trop pleins, alors nous devons regarder à travers
une très longue liste chaînée.
Et c'est en quelque sorte vaincre le point.
Voici donc un exemple où j'ai quatre seaux.
Jusqu'à présent, j'ai un éléphant et un blaireau dans mon HashSet.
C'est une assez bonne situation, non?
Chaque élément a zéro ou un élément.
Maintenant, nous mettons deux autres éléments dans notre HashSet.
buckets elements
------- -------
0 elephant
1 otter
2 badger
3 cat
Ce n'est pas trop mal non plus.
Chaque seau n'a qu'un seul élément. Donc, si je veux savoir, est-ce que ça contient du panda?
Je peux regarder très rapidement le seau numéro 1 et ce n'est pas
là et
Je savais que ce n'était pas dans notre collection.
Si je veux savoir s'il contient du chat, je regarde le seau
numéro 3,
Je trouve le chat, je sais très vite si c'est dans notre
collection.
Et si j'ajoute du koala, eh bien ce n'est pas si mal.
buckets elements
------- -------
0 elephant
1 otter -> koala
2 badger
3 cat
Peut-être maintenant au lieu de dans le seau numéro 1 en ne regardant que
un élément,
Je dois en regarder deux.
Mais au moins je n'ai pas à regarder l'éléphant, le blaireau et
chat.
Si je cherche encore du panda, il ne peut être que dans un seau
numéro 1 et
Je n'ai pas à regarder autre chose qu'une loutre et
koala.
Mais maintenant, je mets l'alligator dans le seau numéro 1 et vous pouvez
voir peut-être où cela va.
Que si le seau numéro 1 continue de grossir de plus en plus et
plus gros, alors je dois essentiellement regarder à travers tous
ces éléments pour trouver
quelque chose qui devrait être dans le compartiment numéro 1.
buckets elements
------- -------
0 elephant
1 otter -> koala ->alligator
2 badger
3 cat
Si je commence à ajouter des chaînes à d'autres compartiments,
à droite, le problème devient de plus en plus grand dans chaque
seau simple.
Comment pouvons-nous empêcher nos seaux de devenir trop pleins?
La solution ici est que
"the HashSet can automatically
resize the number of buckets."
Il y a le HashSet se rend compte que les seaux deviennent
trop plein.
Il perd cet avantage de cette recherche unique
éléments.
Et cela ne fera que créer plus de seaux (généralement deux fois comme avant) et
puis placez les éléments dans le bon seau.
Voici donc notre implémentation de base de HashSet avec des
enchaînement. Maintenant, je vais créer un "HashSet auto-redimensionnant".
Ce HashSet va se rendre compte que les seaux sont
devenir trop plein et
il a besoin de plus de seaux.
loadFactor est un autre champ de notre classe HashSet.
loadFactor représente le nombre moyen d'éléments par
seau,
au-dessus duquel nous voulons redimensionner.
loadFactor est un équilibre entre l'espace et le temps.
Si les godets sont trop pleins, nous redimensionnerons.
Cela prend du temps, bien sûr, mais
cela peut nous faire gagner du temps sur la route si les seaux sont un
un peu plus vide.
Voyons un exemple.
Voici un HashSet, nous avons ajouté quatre éléments jusqu'à présent.
Éléphant, chien, chat et poisson.
buckets elements
------- -------
0
1 elephant
2 cat ->dog
3 fish
4
5
À ce stade, j'ai décidé que le loadFactor, le
seuil,
le nombre moyen d'éléments par seau que je vais bien
avec, est de 0,75.
Le nombre de godets est buckets.length, qui est de 6, et
à ce stade, notre HashSet a quatre éléments, de sorte que le
la taille actuelle est de 4.
Nous allons redimensionner notre HashSet, c'est-à-dire que nous ajouterons plus de compartiments,
lorsque le nombre moyen d'éléments par seau dépasse
le loadFactor.
C'est lorsque la taille actuelle est divisée par des seaux. La longueur est
supérieur à loadFactor.
À ce stade, le nombre moyen d'éléments par compartiment
est 4 divisé par 6.
4 éléments, 6 seaux, soit 0,67.
C'est moins que le seuil que j'ai fixé à 0,75, nous sommes donc
d'accord.
Nous n'avons pas besoin de redimensionner.
Mais maintenant, disons que nous ajoutons la marmotte.
buckets elements
------- -------
0
1 elephant
2 woodchuck-> cat ->dog
3 fish
4
5
La marmotte se retrouverait dans le seau numéro 3.
À ce stade, la taille actuelle est 5.
Et maintenant, le nombre moyen d'éléments par seau
est la taille actuelle divisée par buckets.length.
Cela fait 5 éléments divisés par 6 seaux soit 0,83.
Et cela dépasse le loadFactor qui était de 0,75.
Afin de résoudre ce problème, afin de rendre le
des seaux peut-être un peu
plus vide de sorte que des opérations comme déterminer si un
le seau contient
un élément sera un peu moins complexe, je veux redimensionner
mon HashSet.
Le redimensionnement du HashSet prend deux étapes.
Je vais d'abord doubler le nombre de seaux, j'avais 6 seaux,
maintenant, je vais avoir 12 seaux.
Notez ici que le loadFactor que j'ai défini à 0,75 reste le même.
Mais le nombre de seaux modifiés est de 12,
le nombre d'éléments est resté le même, est 5.
5 divisé par 12 est d'environ 0,42, ce qui est bien en deçà de notre
facteur de charge,
nous allons donc bien maintenant.
Mais nous n'avons pas fini parce que certains de ces éléments sont en
le mauvais seau maintenant.
Par exemple, l'éléphant.
L'éléphant était dans le seau numéro 2 car le nombre de
personnages en éléphant
avait 8 ans.
Nous avons 6 seaux, 8 moins 6 est 2.
C'est pourquoi il s'est retrouvé au numéro 2.
Mais maintenant que nous avons 12 seaux, 8 mod 12 est 8, donc
l'éléphant n'appartient plus au seau numéro 2.
L'éléphant appartient au seau numéro 8.
Et la marmotte?
Woodchuck est celui qui a commencé tout ce problème.
La marmotte s'est retrouvée dans le seau numéro 3.
Parce que 9 mod 6 est 3.
Mais maintenant, nous faisons 9 mod 12.
9 le mod 12 est 9, la marmotte passe au numéro 9.
Et vous voyez l'avantage de tout cela.
Désormais, le compartiment numéro 3 ne comporte que deux éléments, alors qu'auparavant il en avait 3.
Voici donc notre code,
où nous avions notre HashSet avec un chaînage séparé
n'a fait aucun redimensionnement.
Maintenant, voici une nouvelle implémentation où nous utilisons le redimensionnement.
La plupart de ce code est le même,
nous allons encore déterminer s'il contient le
valeur déjà.
Si ce n'est pas le cas, nous déterminerons dans quel seau il
devrait entrer et
puis ajoutez-le à ce compartiment, ajoutez-le à cette LinkedList.
Mais maintenant, nous incrémentons le champ currentSize.
currentSize était le champ qui gardait une trace du nombre
d'éléments dans notre HashSet.
Nous allons l'incrémenter, puis nous allons regarder
à la charge moyenne,
le nombre moyen d'éléments par seau.
Nous ferons cette division ici.
Nous devons faire un peu de casting ici pour nous assurer
que nous obtenons un double.
Et puis, nous comparerons cette charge moyenne au champ
que j'ai défini comme
0,75 lorsque j'ai créé ce HashSet, par exemple, qui était
le loadFactor.
Si la charge moyenne est supérieure à loadFactor,
cela signifie qu'il y a trop d'éléments par seau sur
moyenne, et je dois réinsérer.
Voici donc notre implémentation de la méthode de réinsertion
tous les éléments.
Tout d'abord, je vais créer une variable locale appelée oldBuckets.
Qui fait référence aux seaux tels qu'ils sont actuellement
avant de commencer à tout redimensionner.
Remarque Je ne crée pas encore de nouveau tableau de listes liées.
Je ne fais que renommer les compartiments en anciens compartiments.
Rappelez-vous maintenant que les seaux étaient un domaine dans notre classe, je vais
pour créer maintenant un nouveau tableau
de listes liées, mais cela aura deux fois plus d'éléments
comme il l'a fait la première fois.
Maintenant, je dois faire la réinsertion,
Je vais parcourir tous les anciens seaux.
Chaque élément de oldBuckets est une LinkedList de chaînes
c'est un seau.
Je vais passer par ce seau et obtenir chaque élément
seau.
Et maintenant je vais le réinsérer dans les newBuckets.
J'obtiendrai son hashCode.
Je vais déterminer de quel indice il s'agit.
Et maintenant, je reçois le nouveau compartiment, la nouvelle LinkedList de
cordes et
Je vais l'ajouter à ce nouveau seau.
Donc, pour récapituler, les HashSets comme nous l'avons vu sont des tableaux de Linked
Listes ou seaux.
Un HashSet auto-redimensionnant peut réaliser en utilisant un certain rapport ou
capacity = N/0.75
pour éviter de ressasser, mais ma pensée initiale vient d'être définieload factor = 1
. Y aurait-il des inconvénients à cette approche? Pourquoi le facteur de charge affecterait-get()
ilput()
les coûts d'exploitation?