Descripción general de la tabla hash simple
Como actualización, una tabla hash es una forma de almacenar un valor bajo una clave específica en una estructura de datos. Por ejemplo, podría almacenar el valor "a"
debajo de la clave 1
y luego recuperarlo buscando la clave 1
en la tabla hash.
El ejemplo más simple de una tabla hash que se me ocurre fuera de mi cabeza es una tabla hash que solo puede almacenar enteros, donde la clave para la entrada de la tabla hash también es el valor que se está almacenando. Digamos que su tabla es de tamaño 8, y es básicamente una matriz en la memoria:
---------------------------------
| | | | | | | | |
---------------------------------
0 1 2 3 4 5 6 7
Función hash
Las funciones hash le dan un índice sobre dónde almacenar su valor. Una función hash bastante simple para esta tabla sería agregar 1 al valor que desea almacenar y luego modificarlo en 8 (el tamaño de la tabla). En otras palabras, su función hash es (n+1)%8
dónde n
está el número entero que desea almacenar.
Inserta
Si desea insertar un valor en esta tabla hash, llame a su función hash (en este caso (n+1)%8
) sobre el valor que desea insertar para obtener un índice. Por ejemplo, si queremos insertar 14, llamaríamos (14 + 1) % 8
y obtendríamos índice 7
, por lo que insertaríamos el valor en index 7
.
---------------------------------
| | | | | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Del mismo modo, podemos insertar 33, 82 y 191 así:
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Colisiones
Pero, ¿qué sucede si intentamos insertar algo que colisionaría con una entrada? 2 debe ir en el índice 3
, pero está en 82. Hay varias formas de resolver este problema, la más simple es llamar a nuestra función hash una y otra vez hasta que encontremos un espacio vacío.
Entonces la lógica es la siguiente:
- (2 + 1)% 8 = 3
- El índice 3 está lleno
- Vuelva a enchufar 3 en nuestra función hash. ( 3 + 1)% 8 = 4 , que está vacío.
- Coloque nuestro valor en el índice 4 .
Ahora la tabla hash se ve así, con el valor 2 almacenado en el índice 4
.
---------------------------------
|191| |33 |82 |2 | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
La desventaja de esta solución es que muy pronto, ¡nuestra mesa se llenará! Si sabe que el tamaño de sus datos es limitado, esto no debería ser un problema siempre que su tabla sea lo suficientemente grande como para contener todos los valores posibles. Si desea poder sostener más, puede manejar las colisiones de manera diferente. Volvamos a donde estábamos antes de insertar 2.
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Si recuerda, (2+1)%8
nos da un índice 3
, que se toma. Si no desea que se llene su tabla hash, puede usar cada índice de la tabla como una lista vinculada y agregarla a la lista en ese índice. Entonces, en lugar de llamar a la función hash nuevamente, simplemente agregaremos a la lista en el índice 3
:
-----
| 2 |
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Esta lista puede crecer tanto como lo permita la memoria. Puedo insertar 18, y solo se agregará a 2:
-----
|18 |
-----
| 2 |
---------------------------------
|191| |33 |82 | | | |14 |
---------------------------------
0 1 2 3 4 5 6 7
Búsquedas
La búsqueda de valores en su tabla hash es rápida, dado que su tabla hash es de un tamaño bastante grande. Simplemente llame a su función hash y obtenga el índice. Digamos que quieres ver si 82 está en tu mesa. La función de búsqueda llamaría (82+1)%8
= 3
, y miraría el elemento en el índice 3
, y lo devolvería por usted. Si buscó 16, la función de búsqueda se vería en el índice 1
y vería que no existe.
¡Las búsquedas también necesitan manejar colisiones!
Si intenta buscar el valor 2, su tabla hash tendría que usar la misma lógica de colisión que usó para almacenar los datos que para recuperarlos. Dependiendo de la forma en que funcione su tabla hash, puede cambiar la clave una y otra vez hasta encontrar la entrada que está buscando (o encontrar un espacio en blanco), o puede recorrer su lista vinculada hasta encontrar el elemento (o llegó al final de la lista)
Resumen
Por lo tanto, las tablas hash son una buena forma de almacenar y acceder rápidamente a pares clave-valor. En este ejemplo, utilizamos la misma clave que el valor, pero en las tablas hash del mundo real las claves no son tan limitadas. Las funciones de hash funcionarán en las teclas para generar un índice, y luego la clave / valor se puede almacenar en ese índice. Las tablas hash en realidad no están destinadas a ser iteradas, aunque es posible hacerlo. Como puede ver, las tablas hash pueden tener muchos espacios en blanco, y recorrerlas sería una pérdida de tiempo. Incluso si la tabla hash tiene lógica para omitir las búsquedas de espacios en blanco en su iterador, sería mejor utilizar una estructura de datos diseñada para iteradores, como listas vinculadas.