Estructuras de datos y algoritmos

Tutorial de estructura de datos de tabla hash

Tutorial de estructura de datos de tabla hash
En informática, la palabra "mapa" significa vincular un elemento de un conjunto a otro elemento de otro conjunto. Imagina que en una página, hay palabras en un círculo a la izquierda, y en el lado derecho de la misma página, hay otro círculo dentro del cual hay otras palabras. Suponga que en cada círculo, las palabras están escritas al azar, esparcidas dentro del círculo. Además, suponga que las palabras en el círculo de la izquierda se llaman claves y las palabras en el círculo de la derecha se llaman valores. Si se dibuja una flecha de cada palabra de la izquierda a cada palabra de la derecha, se diría que las claves se han asignado a los valores.

Suponga que es propietario de una gran tienda de provisiones en el condado donde vive. Suponga que vive en un área grande, que no es un área comercial. No eres el único que tiene una tienda de provisiones en la zona; tienes algunos competidores. Y luego se te ocurre que debes registrar los números de teléfono de tus clientes en un cuaderno de ejercicios. Por supuesto, el libro de ejercicios es pequeño y no puede registrar todos los números de teléfono de todos sus clientes.

Entonces decide registrar solo los números de teléfono de sus clientes habituales. Y entonces tienes una tabla con dos columnas. La columna de la izquierda tiene los nombres de los clientes y la columna de la derecha tiene los números de teléfono correspondientes. De esta manera, existe un mapeo entre los nombres de los clientes y los números de teléfono. La columna de la derecha de la tabla se puede considerar como la tabla hash principal. Los nombres de los clientes ahora se denominan claves y los números de teléfono se denominan valores. Tenga en cuenta que cuando un cliente se transfiere, tendrá que cancelar su fila, permitiendo que la fila se vacíe o sea reemplazada por la de un nuevo cliente habitual. También tenga en cuenta que con el tiempo, la cantidad de clientes habituales puede aumentar o disminuir, por lo que la tabla puede crecer o reducirse.

Como otro ejemplo de mapeo, suponga que hay un club de agricultores en un condado. Por supuesto, no todos los agricultores serán miembros del club. Algunos miembros del club no serán socios regulares (asistencia y contribución). El barman puede decidir registrar los nombres de los miembros y su elección de bebida. Desarrolla una tabla de dos columnas. En la columna de la izquierda, escribe los nombres de los socios del club. En la columna de la derecha, escribe la elección de bebida correspondiente.

Aquí hay un problema: hay duplicados en la columna de la derecha. Es decir, el mismo nombre de una bebida se encuentra más de una vez. En otras palabras, diferentes miembros beben la misma bebida dulce o la misma bebida alcohólica, mientras que otros miembros beben una bebida dulce o alcohólica diferente. El barman decide solucionar este problema insertando una columna estrecha entre las dos columnas. En esta columna del medio, comenzando por la parte superior, numera las filas comenzando desde cero (i.mi. 0, 1, 2, 3, 4, etc.), bajando, un índice por fila. Con esto, su problema está resuelto, ya que el nombre de un miembro ahora se asigna a un índice, y no al nombre de una bebida. Entonces, como una bebida se identifica mediante un índice, el nombre de un cliente se asigna al índice correspondiente.

La columna de valores (bebidas) por sí sola forma la tabla hash básica. En la tabla modificada, la columna de índices y sus valores asociados (con o sin duplicados) forman una tabla hash normal; a continuación se proporciona la definición completa de una tabla hash. Las claves (primera columna) no necesariamente forman parte de la tabla hash.

Como otro ejemplo, considere un servidor de red donde un usuario de su computadora cliente puede agregar información, eliminar información o modificar información. Hay muchos usuarios para el servidor.  Cada nombre de usuario corresponde a una contraseña almacenada en el servidor. Quienes mantienen el servidor pueden ver los nombres de usuario y la contraseña correspondiente, y así poder corromper el trabajo de los usuarios.

Entonces, el propietario del servidor decide producir una función que encripta una contraseña antes de que se almacene. Un usuario inicia sesión en el servidor, con su contraseña normal entendida. Sin embargo, ahora, cada contraseña se almacena de forma cifrada. Si alguien ve una contraseña encriptada e intenta iniciar sesión usándola, no funcionará, porque al iniciar sesión, el servidor recibe una contraseña entendida, y no una contraseña encriptada.

En este caso, la contraseña entendida es la clave y la contraseña cifrada es el valor. Si la contraseña cifrada está en una columna de contraseñas cifradas, esa columna es una tabla hash básica. Si esa columna está precedida por otra columna con índices que comienzan desde cero, de modo que cada contraseña cifrada está asociada con un índice, entonces tanto la columna de índices como la columna de contraseña cifrada forman una tabla hash normal. Las claves no son necesariamente parte de la tabla hash.

Tenga en cuenta, en este caso, que cada clave, que es una contraseña entendida, corresponde a un nombre de usuario. Entonces, hay un nombre de usuario que corresponde a una clave que está asignada a un índice, que está asociado con un valor que es una clave encriptada.

La definición de una función hash, la definición completa de una tabla hash, el significado de una matriz y otros detalles se dan a continuación. Necesita tener conocimiento en punteros (referencias) y listas enlazadas, para poder apreciar el resto de este tutorial.

Significado de la función hash y la tabla hash

Formación

Una matriz es un conjunto de ubicaciones de memoria consecutivas. Todas las ubicaciones son del mismo tamaño. Se accede al valor de la primera ubicación con el índice 0; se accede al valor en la segunda ubicación con el índice, 1; se accede al tercer valor con el índice, 2; cuarto con índice, 3; y así. Normalmente, una matriz no puede aumentar ni reducir. Para cambiar el tamaño (longitud) de una matriz, se debe crear una nueva matriz y los valores correspondientes se deben copiar en la nueva matriz. Los valores de una matriz son siempre del mismo tipo.

Función hash

En software, una función hash es una función que toma una clave y produce un índice correspondiente para una celda de matriz. La matriz es de un tamaño fijo (longitud fija). El número de claves es de tamaño arbitrario, generalmente más grande que el tamaño de la matriz. El índice resultante de la función hash se llama valor hash o resumen o código hash o simplemente hash.

Tabla de picadillo

Una tabla hash es una matriz con valores, a cuyos índices se asignan claves. Las claves se asignan indirectamente a los valores. De hecho, se dice que las claves se asignan a los valores, ya que cada índice está asociado con un valor (con o sin duplicados). Sin embargo, la función que hace el mapeo (i.mi. hash) relaciona las claves con los índices de la matriz y no realmente con los valores, ya que puede haber duplicados en los valores. El siguiente diagrama ilustra una tabla hash para los nombres de las personas y sus números de teléfono. Las celdas de la matriz (ranuras) se denominan cubos.

Observe que algunos cubos están vacíos. Una tabla hash no debe tener necesariamente valores en todos sus depósitos. Los valores de los depósitos no deben estar necesariamente en orden ascendente. Sin embargo, los índices con los que están asociados están en orden ascendente. Las flechas indican el mapeo. Observe que las claves no están en una matriz. No tienen que estar en ninguna estructura. Una función hash toma cualquier clave y genera un índice para una matriz. Si no hay ningún valor en el depósito asociado con el índice hash, se puede poner un nuevo valor en ese depósito. La relación lógica es entre la clave y el índice, y no entre la clave y el valor asociado con el índice.

Los valores de una matriz, como los de esta tabla hash, son siempre del mismo tipo de datos. Una tabla hash (cubos) puede conectar claves a los valores de diferentes tipos de datos. En este caso, los valores de la matriz son todos punteros que apuntan a diferentes tipos de valores.

Una tabla hash es una matriz con una función hash. La función toma una clave y aplica un hash al índice correspondiente, y así conecta las claves a los valores en la matriz. Las claves no tienen que ser parte de la tabla hash.

Por qué matriz y no lista vinculada para tabla hash

La matriz de una tabla hash se puede reemplazar por una estructura de datos de lista vinculada, pero habría un problema. El primer elemento de una lista enlazada está naturalmente en el índice 0; el segundo elemento está naturalmente en el índice 1; el tercero está naturalmente en el índice 2; y así. El problema con la lista vinculada es que para recuperar un valor, la lista debe iterarse, y esto lleva tiempo. Acceder a un valor en una matriz es por acceso aleatorio. Una vez que se conoce el índice, se obtiene el valor sin iteración; este acceso es más rápido.

Colisión

La función hash toma una clave y aplica un hash al índice correspondiente, para leer el valor asociado o para insertar un nuevo valor. Si el propósito es leer un valor, no hay ningún problema (no hay problema), hasta ahora. Sin embargo, si el propósito es insertar un valor, es posible que el índice hash ya tenga un valor asociado, y eso es una colisión; el nuevo valor no se puede poner donde ya existe un valor. Hay formas de solucionar una colisión; consulte a continuación.

Por qué ocurre la colisión

En el ejemplo de la tienda de provisiones anterior, los nombres de los clientes son las claves y los nombres de las bebidas son los valores. Tenga en cuenta que los clientes son demasiados, mientras que la matriz tiene un tamaño limitado y no puede aceptar a todos los clientes. Por lo tanto, solo las bebidas de los clientes habituales se almacenan en la matriz. La colisión ocurriría cuando un cliente no habitual se vuelve habitual. Los clientes de la tienda forman un conjunto grande, mientras que la cantidad de cubos para los clientes en la matriz es limitada.

Con las tablas hash, son los valores de las claves que son muy probables, los que se registran. Cuando una llave que no era probable, se vuelve probable, probablemente habrá una colisión. De hecho, la colisión siempre ocurre con tablas hash.

Conceptos básicos de resolución de colisiones

Dos enfoques para la resolución de colisiones se denominan encadenamiento separado y direccionamiento abierto. En teoría, las claves no deberían estar en la estructura de datos o no deberían formar parte de la tabla hash. Sin embargo, ambos enfoques requieren que la columna de claves preceda a la tabla hash y se convierta en parte de la estructura general. En lugar de que las claves estén en la columna de claves, los punteros a las claves pueden estar en la columna de claves.

Una tabla hash práctica incluye una columna de claves, pero esta columna de claves no es oficialmente parte de la tabla hash.

Cualquiera de los enfoques de resolución puede tener depósitos vacíos, no necesariamente al final de la matriz.

Encadenamiento separado

En el encadenamiento por separado, cuando ocurre una colisión, el nuevo valor se agrega a la derecha (ni arriba ni abajo) del valor chocado. Entonces dos o tres valores terminan teniendo el mismo índice. Rara vez más de tres deberían tener el mismo índice.

¿Puede más de un valor tener realmente el mismo índice en una matriz?? - No. Entonces, en muchos casos, el primer valor para el índice es un puntero a una estructura de datos de lista vinculada, que contiene uno, dos o tres valores colisionados. El siguiente diagrama es un ejemplo de una tabla hash para el encadenamiento por separado de clientes y sus números de teléfono:

Los cubos vacíos están marcados con la letra x. El resto de las ranuras tienen punteros a listas vinculadas. Cada elemento de la lista vinculada tiene dos campos de datos: uno para el nombre del cliente y otro para el número de teléfono. Ocurre conflicto por las llaves: Peter Jones y Suzan Lee. Los valores correspondientes constan de dos elementos de una lista vinculada.

Para claves en conflicto, el criterio para insertar valor es el mismo criterio usado para ubicar (y leer) el valor.

Direccionamiento abierto

Con el direccionamiento abierto, todos los valores se almacenan en la matriz de cubos. Cuando ocurre un conflicto, el nuevo valor se inserta en un balde vacío nuevo el valor correspondiente al conflicto, siguiendo algún criterio. El criterio utilizado para insertar un valor en conflicto es el mismo criterio utilizado para localizar (buscar y leer) el valor.

El siguiente diagrama ilustra la resolución de conflictos con direccionamiento abierto:

La función hash toma la clave, Peter Jones, usa el índice 152 y almacena su número de teléfono en el depósito asociado. Después de algún tiempo, la función hash hace un hash del mismo índice, 152 de la clave, Suzan Lee, chocando con el índice de Peter Jones. Para resolver esto, el valor de Suzan Lee se almacena en el depósito del siguiente índice, 153, que estaba vacío. La función hash calcula el índice, 153 para la clave, Robin Hood, pero este índice ya se ha utilizado para resolver el conflicto de una clave anterior. Entonces, el valor de Robin Hood se coloca en el siguiente cubo vacío, que es el del índice 154.

Métodos de resolución de conflictos para encadenamiento separado y direccionamiento abierto

El encadenamiento separado tiene sus métodos para resolver conflictos, y el direccionamiento abierto también tiene sus propios métodos para resolver conflictos.

Métodos para resolver conflictos de encadenamiento separados

Los métodos para encadenar tablas hash por separado se explican brevemente ahora:

Encadenamiento independiente con listas vinculadas

Este método es como se explicó anteriormente. Sin embargo, cada elemento de la lista vinculada no debe tener necesariamente el campo clave (p.gramo. campo de nombre de cliente arriba).

Encadenamiento independiente con celdas de encabezado de lista

En este método, el primer elemento de la lista vinculada se almacena en un depósito de la matriz. Esto es posible, si el tipo de datos de la matriz es el elemento de la lista vinculada.

Encadenamiento separado con otras estructuras

Cualquier otra estructura de datos, como el árbol de búsqueda binaria autoequilibrado que admita las operaciones necesarias, se puede utilizar en lugar de la lista vinculada; consulte más adelante.

Métodos para resolver conflictos de direccionamiento abierto

Un método para resolver conflictos en el direccionamiento abierto se llama secuencia de sondeo. A continuación, se explican brevemente tres secuencias de sondas bien conocidas:

Palpado lineal

Con el sondeo lineal, cuando ocurre un conflicto, se busca el balde vacío más cercano debajo del balde en conflicto. Además, con el sondeo lineal, tanto la clave como su valor se almacenan en el mismo depósito.

Palpado cuadrático

Suponga que el conflicto ocurre en el índice H. La siguiente ranura vacía (cubo) en el índice H + 12 se utiliza; si eso ya está ocupado, entonces el siguiente vacío en H + 22 se usa, si ya está ocupado, entonces el siguiente vacío en H + 32 se usa, etc. Hay variantes de esto.

Hash doble

Con doble hash, hay dos funciones hash. El primero calcula (hash) el índice. Si ocurre un conflicto, el segundo usa la misma clave para determinar qué tan abajo se debe insertar el valor. Hay más en esto - ver más adelante.

Función hash perfecta

Una función hash perfecta es una función hash que no puede resultar en ninguna colisión. Esto puede suceder cuando el conjunto de claves es relativamente pequeño y cada clave se asigna a un entero particular en la tabla hash.

En el conjunto de caracteres ASCII, los caracteres en mayúsculas se pueden asignar a sus letras minúsculas correspondientes mediante una función hash. Las letras se representan en la memoria de la computadora como números. En el juego de caracteres ASCII, A es 65, B es 66, C es 67, etc. y a es 97, b es 98, c es 99, etc. Para mapear de A a a, sume 32 a 65; para mapear de B a b, sume 32 a 66; para mapear de C a c, sume 32 a 67; y así. Aquí, las letras mayúsculas son las claves y las minúsculas son los valores. La tabla hash para esto puede ser una matriz cuyos valores son los índices asociados. Recuerde, los depósitos de la matriz pueden estar vacíos. Entonces, los cubos en la matriz de 64 a 0 pueden estar vacíos. La función hash simplemente agrega 32 al número de código en mayúsculas para obtener el índice y, por lo tanto, la letra minúscula. Esta función es una función hash perfecta.

Hash de índices enteros a enteros

Hay diferentes métodos para hacer hash de números enteros. Uno de ellos se llama Método de división de módulo (función).

La función hash de división de módulo

Una función en el software de computadora no es una función matemática. En informática (software), una función consta de un conjunto de declaraciones precedidas por argumentos. Para la función de división de módulo, las claves son números enteros y se asignan a índices de la matriz de cubos. El conjunto de claves es grande, por lo que solo se asignarían las claves que es muy probable que ocurran en la actividad. Entonces, las colisiones ocurren cuando se deben mapear claves poco probables.

En la declaración,

20/6 = 3R2

20 es el dividendo, 6 es el divisor y 3 resto 2 es el cociente. El resto 2 también se llama módulo. Nota: es posible tener un módulo de 0.

Para este hash, el tamaño de la tabla suele ser una potencia de 2, e.gramo. 64 = 26 o 256 = 28, etc.  El divisor de esta función hash es un número primo cercano al tamaño de la matriz. Esta función divide la clave por el divisor y devuelve el módulo. El módulo es el índice de la matriz de cubos. El valor asociado en el depósito es un valor de su elección (valor para la clave).

Hash de teclas de longitud variable

Aquí, las claves del juego de claves son textos de diferentes longitudes. Se pueden almacenar diferentes enteros en la memoria usando el mismo número de bytes (el tamaño de un carácter en inglés es un byte). Cuando diferentes claves tienen diferentes tamaños de bytes, se dice que son de longitud variable. Uno de los métodos para aplicar hash a longitudes variables se llama Radix Conversion Hashing.

Hash de conversión de radix

En una cadena, cada carácter de la computadora es un número. En este método,

Código hash (índice) = x0ak − 1+X1ak − 2+… + Xk − 2a1+Xk − 1a0

Donde (x0, x1,…, xk − 1) son los caracteres de la cadena de entrada y a es una base, e.gramo. 29 (ver más adelante). k es el número de caracteres en la cadena. Hay más en esto - ver más adelante.

Claves y valores

En un par clave / valor, un valor puede no ser necesariamente un número o texto. También puede ser un récord. Un registro es una lista escrita horizontalmente. En un par clave / valor, cada clave puede referirse a algún otro texto, número o registro.

Matriz asociativa

Una lista es una estructura de datos, donde los elementos de la lista están relacionados y hay un conjunto de operaciones que operan en la lista. Cada elemento de la lista puede constar de un par de elementos. La tabla hash general con sus claves se puede considerar como una estructura de datos, pero es más un sistema que una estructura de datos. Las claves y sus valores correspondientes no son muy dependientes entre sí. No están muy relacionados entre sí.

Por otro lado, una matriz asociativa es algo similar, pero las claves y sus valores son muy dependientes entre sí; están muy relacionados entre sí. Por ejemplo, puede tener una matriz asociativa de frutas y sus colores. Cada fruta tiene naturalmente su color. El nombre de la fruta es la clave; el color es el valor. Durante la inserción, cada clave se inserta con su valor. Al eliminar, cada clave se elimina con su valor.

Una matriz asociativa es una estructura de datos de tabla hash compuesta por pares clave / valor, donde no hay duplicados para las claves. Los valores pueden tener duplicados. En esta situación, las claves son parte de la estructura. Es decir, las claves deben almacenarse, mientras que, con la tabla hast general, las claves no tienen que almacenarse. El problema de los valores duplicados se resuelve naturalmente mediante los índices de la matriz de cubos. No confunda entre valores duplicados y colisión en un índice.

Dado que una matriz asociativa es una estructura de datos, tiene al menos las siguientes operaciones:

Operaciones de matrices asociativas

insertar o agregar

Esto inserta un nuevo par clave / valor en la colección, asignando la clave a su valor.

reasignar

Esta operación reemplaza el valor de una clave en particular por un nuevo valor.

eliminar o eliminar

Esto elimina una clave más su valor correspondiente.

buscar

Esta operación busca el valor de una clave en particular y devuelve el valor (sin eliminarlo).

Conclusión

La estructura de datos de una tabla hash consta de una matriz y una función. La función se llama función hash. La función asigna claves a valores en la matriz a través de los índices de la matriz. Las claves no deben formar parte necesariamente de la estructura de datos. El conjunto de claves suele ser mayor que los valores almacenados. Cuando ocurre una colisión, se resuelve mediante el enfoque de encadenamiento separado o el enfoque de direccionamiento abierto. Una matriz asociativa es un caso especial de la estructura de datos de la tabla hash.

Cómo cambiar el tamaño, el color y el esquema del puntero del mouse y del cursor en Windows 10
El puntero y el cursor del mouse en Windows 10 son aspectos muy importantes del sistema operativo. Esto también se puede decir de otros sistemas opera...
Motores de juegos gratuitos y de código abierto para desarrollar juegos de Linux
Este artículo cubrirá una lista de motores de juegos de código abierto y gratuitos que se pueden usar para desarrollar juegos 2D y 3D en Linux. Existe...
Tutorial de Shadow of the Tomb Raider para Linux
Shadow of the Tomb Raider es la duodécima incorporación a la serie Tomb Raider, una franquicia de juegos de acción y aventuras creada por Eidos Montre...