Si los cubos se llenan demasiado, entonces tenemos que mirar a través de
Una larga lista vinculada.
Y eso es como derrotar el punto.
Así que aquí hay un ejemplo donde tengo cuatro cubos.
Tengo elefante y tejón en mi HashSet hasta ahora.
Esta es una muy buena situación, ¿verdad?
Cada elemento tiene cero o uno elementos.
Ahora ponemos dos elementos más en nuestro HashSet.
buckets elements
------- -------
0 elephant
1 otter
2 badger
3 cat
Esto tampoco es tan malo.
Cada cubo solo tiene un elemento. Entonces, si quiero saber, ¿esto contiene panda?
Puedo ver rápidamente el cubo número 1 y no es
alli y
Sabía que no está en nuestra colección.
Si quiero saber si contiene gato, miro el cubo
numero 3,
Encuentro gato, sé muy rápidamente si está en nuestro
colección.
¿Qué pasa si agrego koala? Bueno, eso no es tan malo.
buckets elements
------- -------
0 elephant
1 otter -> koala
2 badger
3 cat
Tal vez ahora en lugar de en el cubo número 1 solo mirando
un elemento
Necesito mirar a las dos.
Pero al menos no tengo que mirar elefante, tejón y
gato.
Si nuevamente estoy buscando panda, solo puede estar en el cubo
número 1 y
No tengo que mirar nada más que nutria y
coala.
Pero ahora pongo cocodrilo en el cubo número 1 y puedes
mira quizás a dónde va esto.
Que si el cubo número 1 sigue creciendo y creciendo
más grande, entonces básicamente tengo que mirar a través de todos
esos elementos para encontrar
algo que debería estar en el cubo número 1.
buckets elements
------- -------
0 elephant
1 otter -> koala ->alligator
2 badger
3 cat
Si empiezo a agregar cadenas a otros cubos,
bien, el problema se hace cada vez más grande en cada
solo cubo
¿Cómo evitamos que nuestros cubos se llenen demasiado?
La solución aquí es que
"the HashSet can automatically
resize the number of buckets."
Ahí está el HashSet se da cuenta de que los cubos se están poniendo
muy lleno.
Está perdiendo esta ventaja de esta búsqueda completa de
elementos.
Y solo creará más cubos (generalmente el doble que antes) y
luego coloque los elementos en el cubo correcto.
Así que aquí está nuestra implementación básica de HashSet con separador
encadenamiento Ahora voy a crear un "HashSet auto-redimensionable".
Este HashSet se dará cuenta de que los cubos son
llenándose demasiado y
Necesita más cubos.
loadFactor es otro campo en nuestra clase HashSet.
loadFactor representa el número promedio de elementos por
Cubeta,
por encima del cual queremos cambiar el tamaño.
loadFactor es un equilibrio entre espacio y tiempo.
Si los cubos se llenan demasiado, cambiaremos el tamaño.
Eso lleva tiempo, por supuesto, pero
puede ahorrarnos tiempo en el futuro si los cubos son un
Un poco más vacío.
Veamos un ejemplo.
Aquí hay un HashSet, hasta ahora hemos agregado cuatro elementos.
Elefante, perro, gato y pez.
buckets elements
------- -------
0
1 elephant
2 cat ->dog
3 fish
4
5
En este punto, he decidido que loadFactor, el
límite,
el número promedio de elementos por cubo que estoy bien
con, es 0.75.
El número de cubos es buckets.length, que es 6, y
en este punto nuestro HashSet tiene cuatro elementos, por lo que el
El tamaño actual es 4.
Redimensionaremos nuestro HashSet, es decir, agregaremos más cubos,
cuando el número promedio de elementos por cubo excede
el loadFactor.
Es entonces cuando el tamaño actual dividido por cubos. Longitud es
mayor que loadFactor.
En este punto, el número promedio de elementos por cubo
es 4 dividido por 6.
4 elementos, 6 cubos, eso es 0.67.
Eso es menos que el umbral que establecí de 0,75, así que estamos
bueno.
No necesitamos cambiar el tamaño.
Pero ahora digamos que agregamos marmota.
buckets elements
------- -------
0
1 elephant
2 woodchuck-> cat ->dog
3 fish
4
5
La marmota terminaría en el cubo número 3.
En este punto, el tamaño actual es 5.
Y ahora el número promedio de elementos por cubo
es el tamaño actual dividido por buckets.length.
Eso es 5 elementos divididos por 6 cubos es 0.83.
Y esto excede el loadFactor que era 0.75.
Para abordar este problema, para hacer que el
cubos tal vez un poco
más vacío para que las operaciones como determinar si un
el cubo contiene
un elemento será un poco menos complejo, quiero cambiar el tamaño
mi HashSet.
Cambiar el tamaño del HashSet tiene dos pasos.
Primero doblaré el número de cubos, tuve 6 cubos,
ahora voy a tener 12 cubos.
Tenga en cuenta que el loadFactor que configuré en 0.75 permanece igual.
Pero el número de cubos cambiados es 12,
el número de elementos se mantuvo igual, es 5.
5 dividido por 12 es alrededor de 0,42, eso está muy por debajo de nuestro
factor de carga,
así que estamos bien ahora.
Pero no hemos terminado porque algunos de estos elementos están en
El cubo equivocado ahora.
Por ejemplo, elefante.
Elefante estaba en el cubo número 2 porque el número de
personajes en elefante
fue 8.
Tenemos 6 cubos, 8 menos 6 es 2.
Por eso terminó en el número 2.
Pero ahora que tenemos 12 cubos, 8 mod 12 es 8, entonces
el elefante ya no pertenece al cubo número 2.
El elefante pertenece al cubo número 8.
¿Qué hay de la marmota?
La marmota fue la que inició todo este problema.
La marmota terminó en el cubo número 3.
Porque 9 mod 6 es 3.
Pero ahora hacemos 9 mod 12.
9 mod 12 es 9, la marmota va al cubo número 9.
Y ves la ventaja de todo esto.
Ahora el cubo número 3 solo tiene dos elementos, mientras que antes tenía 3.
Así que aquí está nuestro código,
donde teníamos nuestro HashSet con encadenamiento separado que
no hizo ningún cambio de tamaño.
Ahora, aquí hay una nueva implementación donde usamos el cambio de tamaño.
La mayor parte de este código es el mismo,
todavía vamos a determinar si contiene el
valor ya.
Si no es así, entonces descubriremos qué cubeta
debería entrar y
luego agréguelo a ese cubo, agréguelo a esa LinkedList.
Pero ahora incrementamos el campo currentSize.
currentSize fue el campo que realizó un seguimiento del número
de elementos en nuestro HashSet.
Vamos a aumentarlo y luego vamos a mirar
a la carga promedio,
El número promedio de elementos por cubo.
Haremos esa división aquí abajo.
Tenemos que hacer un poco de casting aquí para asegurarnos
Que tenemos un doble.
Y luego, compararemos esa carga promedio con el campo
que he establecido como
0.75 cuando creé este HashSet, por ejemplo, que era
el loadFactor.
Si la carga promedio es mayor que el factor de carga,
eso significa que hay demasiados elementos por cubo en
promedio, y necesito reinsertarme.
Así que aquí está nuestra implementación del método para reinsertar
Todos los elementos.
Primero, crearé una variable local llamada oldBuckets.
Que se refiere a los cubos tal como están actualmente
antes de comenzar a cambiar el tamaño de todo.
Tenga en cuenta que todavía no estoy creando una nueva matriz de listas vinculadas.
Solo estoy cambiando el nombre de los cubos como oldBuckets.
Ahora recuerda que los cubos eran un campo en nuestra clase, voy
para crear ahora una nueva matriz
de listas enlazadas pero esto tendrá el doble de elementos
como lo hizo la primera vez.
Ahora necesito hacer la reinserción,
Voy a recorrer todos los viejos cubos.
Cada elemento en oldBuckets es un LinkedList de cadenas
Eso es un balde.
Revisaré ese cubo y obtendré cada elemento en ese
Cubeta.
Y ahora lo voy a reinsertar en los nuevos Buckets.
Obtendré su hashCode.
Descubriré qué índice es.
Y ahora obtengo el nuevo cubo, la nueva LinkedList de
cuerdas y
Lo agregaré a ese nuevo cubo.
En resumen, los HashSets, como hemos visto, son matrices de Linked
Listas o cubos.
Un HashSet auto-redimensionable puede darse cuenta usando alguna relación o
capacity = N/0.75
para evitar repetir, pero mi pensamiento inicial se acaba de establecerload factor = 1
. ¿Habría inconvenientes en ese enfoque? ¿Por qué afectaría el factor de cargaget()
y losput()
costos de operación?