Sesión 06 - Hashing

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 95

Prof.

Robert Espinoza

Búsqueda por transformación de


claves (Hash)
Métodos de Dispersión

 Los algoritmos cuya complejidad son del orden de


O(log2(n)) suelen ser más que aceptables en la
búsqueda interna, pero es posible que no lo sean en
otras situaciones como la búsqueda externa.
 Una estrategia alternativa es usar un método que nos
diga directamente en que posición está el elemento
cuya clave proporcionamos, es decir localizar el dato
en forma directa, sin recorrer algunos datos antes de
localizar al buscado.
 Éste método se usa para implementar inserciones,
eliminaciones y búsquedas en un tiempo medio
constante, independiente del número de elementos.
Métodos de Dispersión

 Permite aumentar la velocidad de búsqueda sin


necesidad de tener los elementos ordenados.
 Todos los elementos identificados por una clave que
debe de ser única.
 Para usar esta estrategia necesitamos:
 Una estructura llamada tabla de dispersión que
almacene las claves con un valor asociado para acceder
directamente a cualquier posición.
 Una función llamada de dispersión que dada una clave,
nos devuelva directamente la posición donde debe
guardarse el elemento de esa clave.
Tablas de dispersión (Hashing tables)
Tablas Hash

 Una tabla hash, matriz asociativa, mapa hash, tabla


de dispersión o tabla fragmentada es una estructura
de datos que asocia llaves o claves con valores.
 Funciona transformando la clave con una función
hash en un hash, un número que identifica la posición
(casilla o cubeta) donde la tabla hash localiza el valor
deseado.
 La operación principal que soporta de manera
eficiente es la búsqueda: permite el acceso a los
elementos (teléfono y dirección, por ejemplo)
almacenados a partir de una clave generada (usando
el nombre o número de cuenta, por ejemplo).
Tablas Hash

 La estructura de datos ideal para la tabla de


dispersión es un arreglo de tamaño fijo N que
contiene las claves (elementos de la tabla).
 Una función de dispersión establecerá la
correspondencia de cada clave con algún número en el
intervalo [0, N-1]
 Las tablas de dispersión se usan por ejemplo:
 Para representar diccionarios en los que se busca una
palabra (clave) y se devuelve su definición.
 Para consultar una guía telefónica por nombre (clave)
Tablas Hash

0
1
2 Ana
3
4 Juan
5 Eva
6
7 Felipe
8
Operaciones básicas en tablas hash

 Las operaciones básicas implementadas en las tablas


hash son:
 inserción(llave, valor)
 búsqueda(llave) que devuelve valor
 borrar(llave).
 Para usar una tabla hash se necesita:
 Una estructura de acceso directo (normalmente un
array).
 Una estructura de datos con una clave
 Una función hash cuyo dominio sea el espacio de claves
y su imagen (o rango) los números naturales.
Operaciones básicas en tablas hash

Inserción
 Para almacenar un elemento en la tabla hash se ha de

convertir su clave a un número.


 Esto se consigue aplicando la función hash a la clave del
elemento.
 El resultado de la función hash ha de mapearse al
espacio de direcciones del vector que se emplea como
soporte obteniéndose un índice válido para la tabla.
 El elemento se almacena en la posición de la tabla
obtenido en el paso anterior.
 Si en la posición de la tabla ya había otro elemento, se
ha producido una colisión que debe resolverse mediante
alguna técnica.
Operaciones básicas en tablas hash

Búsqueda
 Para recuperar los datos, es necesario únicamente

conocer la clave del elemento, a la cual se le aplica la


función hash.
 El valor obtenido se mapea al espacio de direcciones
de la tabla.
 Si el elemento existente en la posición indicada en el

paso anterior tiene la misma clave que la empleada en


la búsqueda, entonces es el deseado.
 Si la clave es distinta, se ha de buscar el elemento según
la técnica empleada para resolver el problema de las
colisiones al almacenar el elemento.
Función de dispersión (Función Hash)
Función de Dispersión (Hash)
 Es una función que transforma una clave a un valor dentro
de un determinado rango que se utiliza como posición para
insertar un objeto dentro de una tabla de dispersión.
Posición = H(clave)
 La función Hash (H) aplicada a la clave genera un índice
entre 0 y N-1 del arreglo de tamaño N, que permite acceder
directamente al elemento.
Función de Dispersión (Hash)

 Una función de dispersión perfecta debe ser:


 Fácil y rápida de calcular.
 Inyectiva, es decir a claves distintas les debería asignar
posiciones distintas dentro del arreglo.
 Sobreyectiva, es decir distribuir homogéneamente las
claves en todas las posiciones del arreglo.
 Si disponemos de dicha función, los algoritmos de
inserción, búsqueda y eliminación son triviales.
 Basta con acceder a la posición que devuelve la función
de dispersión.
Función de Dispersión (Hash)

 Sin embargo, no es fácil encontrar una función de


dispersión perfecta.
 En la mayoría de los casos tenemos un conjunto de claves
posibles muy grande, del que sólo almacenaremos en la
tabla un subconjunto pequeño que no conocemos a priori.
 En esta situación, la función tiene que asociar a varias
claves la misma posición, con lo que deja de ser inyectiva.
 Si la función de dispersión relaciona varias claves con la
misma posición es lo que se conoce como colisión.
H(K1) = d, H(K2) = d y K1 ≠ K2
 En esta situación se complican los algoritmos porque
es necesario resolver la colisión.
Función de Dispersión (Hash)

 Por ejemplo, supongamos que almacenamos la


información de 100 alumnos cuyos códigos son
números del 1 al 100
 En este caso definiremos un arreglo de 100 elementos.
 Los datos de cada alumno ocuparán la posición del
arreglo que corresponda con el código.
 Por lo regular las claves son cadenas de caracteres o
son valores muy grandes o no se corresponden con
los índices del arreglo.
 Se debe usar una función hash que convierta la clave.
 La longitud y las propiedades de las claves influirán en la
elección de una buena función de dispersión.
Funciones Hash más usadas
Función por restas sucesivas

 Esta función se emplea con claves numéricas entre las


que existen huecos de tamaño conocido, obteniéndose
direcciones consecutivas.
 Un ejemplo serían los alumnos de ingeniería en
sistemas que entraron en el año 2005 sus números de
control son consecutivos y está definido el número de
alumnos.
05210800 -05210800 → 0
05210801 -05210800 → 1
05210802 -05210800 → 2

05210899 -05210800 → 99
Función hash por módulo: división

 Consiste en tomar el resto de la división de la clave


entre el número de componentes del arreglo.
 Si N es el tamaño del arreglo y K es la clave a buscar.
H(K) = K mod N
 N debe ser primo o divisible entre muy pocos números.
 Si N no es un número primo, se debe considerar el valor
más cercano.
 Si tuviéramos una tabla con N=10 y todas las claves
terminarían en cero, la dispersión con esta función no
nos valdría.
Función hash por módulo - Ejemplos

 Supongamos que son 100 las direcciones que


debemos asignar a los elementos (0 al 99).
 Consideremos además las claves K1=6359 y K2=8459
 Si N = 100, tenemos
H(K1) = 6359 mod 100 = 59
H(K2) = 8459 mod 100 = 59
Se produce una colisión.
 Si N = 101, primo cercano a 100 el resultado cambia
H(K1) = 6359 mod 101 = 97
H(K2) = 8459 mod 101 = 76
Se ha eliminado la colisión.
Función hash cuadrado

 Consiste en elevar al cuadrado la clave y tomar los


dígitos centrales como dirección.
 El número de dígitos queda determinado por el rango
del índice del arreglo.
 Si K es la clave a buscar, la función estaría definida
como:

H ( K )  dígitos _ centrales ( K 2 )
Función hash cuadrado - Ejemplo

 Sea N = 100 el tamaño del arreglo y sus direcciones


los número entre 0 y 99. Además las claves son
K1 = 7 259 y K2 = 9 359
 Aplicamos la función hash cuadrado

(K1) 2 = 52 693 081


(K2) 2 = 87 590 881

H(K1) = dígitos_centrales (52 693 081) = 93


H(K2) = dígitos_centrales (87 590 881) = 90
Función hash por Plegamiento o
Doblamiento
 Consiste en dividir la clave en partes de igual número
de dígitos aunque la última puede tener menos, y
operar con ellas.
 Se toma como dirección los dígitos menos
significativos.
 Las operaciones entre las partes pueden ser sumas o
multiplicaciones.
 Sea K la clave del dato a buscar. K está formada por
los dígitos d1, d2, ..., dn. La función se define:

H (k )  DígMenSig ((d1 ...d i )  (d i1 ...d j )  ...  (d l ...d n ))


Función hash por Plegamiento o
Doblamiento - Ejemplo
 Sea N = 100 el tamaño del arreglo y sus direcciones los
número entre 0 y 99. Además las claves son
K1 = 7259 y K2 = 9359.

 Aplicamos la función hash por plegamiento


H(K1) = digmensig (72 + 59) = digmensig (131) = 31
H(K2) = digmensig (93 + 59) = digmensig (152) = 52

 De la suma de las partes se toman solamente dos


dígitos porque los índices del arreglo varían del 0 al 99
Función hash por Truncamiento

 Consiste en tomar algunos dígitos de la clave y formar


con ellos una dirección.
 Es el más sencillo, pero ofrece menos uniformidad en
la distribución de claves.
 Sea K la clave del dato a buscar. K está formada por
los dígitos d1, d2, ..., dn. La función sería:

H (k )  ElegirDígitos (d1 , d 2 ...d n )


 La elección de dígitos es arbitraria.
Función hash por Truncamiento -
Ejemplo
 Sea N = 100 el tamaño del arreglo y sus direcciones los
número entre 0 y 99. Además las claves son
K1 = 7259 y K2 = 9359.
 Aplicamos la función hash por truncamiento
H(K1) = ElegirDígitos (7259) = 75
H(K2) = ElegirDígitos (9359) = 95
 En el ejemplo se toman el primero y tercer números de
la clave y se unen de izquierda a derecha.
Función hash con claves de cadena

 En general, cuando aparecen letras en las claves se


suele asociar a cada una un entero con la finalidad de
convertirlas en numéricas.
 Por ejemplo:
A B C D … Z
01 02 03 04 … 27
 Si la clave fuera “ADA”, su equivalente sería 010401.
 Si la clave tuviera letras y números, por ejemplo “Z4F21”,
su equivalente sería 2740621.
 Otra alternativa sería usar el código ASCII asociado.
 Una forma obtenida la clave numérica, se puede usar
cualesquiera de las funciones estudiadas.
Función hash con claves de cadena-
Ejemplos

 Opción 1. Sumar los códigos ASCII.

Método Dispersión1 (Clave, TamañoClave, N)


Valor  ASCII(Clave[0])
Para i desde 1 hasta TamañoClave-1 hacer
valor  valor + ASCII(Clave[i])
fin para
Devolver valor mod N
Fin Método
Función hash con claves de cadena-
Ejemplos
 Es una función fácil de implementar y se ejecuta con
rapidez.
 Pero si el tamaño de la tabla es grande, ésta función
no distribuye bien las claves, por ejemplo:
 Si N = 10007 y las claves tienen 8 caracteres, la función
sólo toma valores entre 0 y 2040 = 255*8
Función hash con claves de cadena-
Ejemplos
 Opción 2. Suponer que la clave tiene al menos tres
caracteres.

Método Dispersión2 (Clave, TamañoClave, N)


Devolver (ASCII(Clave[0]) + 27*ASCII(Clave[1]) +
729 * ASCII(Clave[2])) mod N
Fin Método
Función hash con claves de cadena-
Ejemplos
 Si los primeros caracteres son aleatorios y el tamaño
de la tabla es 10 007, esperaríamos una distribución
bastante homogénea.
 Desafortunadamente, los lenguajes naturales no son
aleatorios
 Aunque hay 273 = 17 576 combinaciones posibles, en un
diccionario el número de combinaciones posibles
diferentes es menor que 3 000.
 Sólo un porcentaje bajo de la tabla puede ser
aprovechada por la dispersión.
Función hash con claves de cadena-
Ejemplos
 Opción 3. Intervienen todos los caracteres de la clave.
Función basada en la regla de Horner.
LongitudClave1

 32i  ascii (clave[ LongitudCl ave  i  1]


i 0

Método Dispersión3 (Clave, TamañoClave, N)


Valor  ASCII(Clave[0])
Para i desde 1 hasta TamañoClave-1 hacer
valor  (32 * valor + ASCII(Clave[i])) mod N
fin para
Devolver valor
Fin Método

Por ejemplo, clave = “abcd”


(ascii(a) + 32.ascii(b) + 322.ascii(c) + 323ascii(d)) mod N
Función hash con claves de cadena-
Ejemplos
 La multiplicación por 32 no es realmente una
multiplicación sino el desplazamiento de cinco bits.
 Con lenguajes que permitan el desbordamiento, el
bucle se debería escribir sin la operación mod, se
aplicaría una sola vez justo antes de volver.
 Si las claves son muy grandes, no se usan todos los
caracteres.
HashCode( ) de Java

 El valor que devuelve el método hashCode( ) es la


alocación en la memoria del objeto, expresada en un
número hexadecimal.
 Todas las clases heredan de java.lang.Object un
sistema básico para el uso de hash, aunque es común
sobreescribir este para obtener una función hash que
maneje de forma más especifica los datos contenidos.
 Normalmente se sobrescribe el método para que se
comporte de forma acorde a la que lo hace .equals(),
es decir, si el método .equals() dice que dos objetos
son iguales, estos han de tener el mismo valor hash.
HashCode( ) de Java

HashCode de los objetos String


 En las primeras versiones de Java, el hash code de un

objeto String se calculaba con base en los primeros 16


dígitos, algo que resultaba muy ineficaz a la hora de
implementar tablas hash, por lo que desde Java 1.2, el
hash code se calcula con base en todos los elementos
del String siguiendo la siguiente fórmula:

𝑛−1

ℎ 𝑠 = ෍ 𝑠 𝑖 . 31𝑛−1−𝑖
𝑖=0
Ejemplo

 En este ejemplo se genera un hash code para un objeto Empleado


basándonos en su ID, el hash code de su nombre y de su departamento.
Cuanto más elaborada sea la función menos colisiones existirán en
nuestro hash.
public class Empleado
{
int IDempleado;
String nombre;
Departamento dept;

// Métodos de la Clase

@Override

public int hashCode()


{
int hash = 1;
hash = hash * 17 + IDempleado;
hash = hash * 31 + nombre.hashCode();
hash = hash * 13 + ((dept == null) ? 0 : dept.hashCode());
return hash;
}
}
Solución de colisiones
Solución de colisiones
 La elección de un método adecuado para resolver
colisiones es tan importante como la elección de una
buena función hash.
 Normalmente, cualquiera sea el método elegido resulta
costoso tratar colisiones.
 Es por ello que se debe hacer un esfuerzo para
encontrar la función que ofrezca la mayor uniformidad
en la distribución de las claves.
 La forma más natural de resolver las colisiones es
reservar una celda por clave, pero puede tener un alto
costo en memoria.
 Se debe analizar otras alternativas para equilibrar el
uso de la memoria con el tiempo de búsqueda.
Solución de colisiones

Métodos más utilizados.


 Dispersión cerrada. Si ocurre una colisión se buscan

celdas alternativas hasta encontrar una vacía.


 Reasignación
 Prueba Lineal
 Prueba cuadrática
 Doble dirección hash
 Arreglos Anidados
 Dispersión abierta. Se amplía la capacidad de cada
casilla de manera dinámica.
 Encadenamiento
Reasignación por prueba lineal

 Detectada la colisión, se recorre el arreglo


secuencialmente a partir del punto de colisión,
buscando el elemento.
 El proceso concluye cuando se halla el elemento o se
llega a una posición vacía.
 Se trata el arreglo como una estructura circular, el
elemento que sigue al último es el primero.
 La principal desventaja es que existe un fuerte
agrupamiento alrededor de ciertas claves, mientras
que en otra puede estar vacío.
 A concentraciones de claves muy frecuentes, la
búsqueda principalmente será secuencial.
Reasignación por prueba lineal - Ejemplo
 Sea A un arreglo de 10 elementos. Sean las claves 25,
43, 56, 35, 54, 13, 80 y 104 asignadas según la función
hash H(K) = K mod 10
0 80
K H(K)
1
25 5
2
43 3
3 43
56 6
4 54
35 5
5 25
54 4
6 56
13 3
7 35
80 0
8 13
104 4
9 104
Reasignación por prueba lineal

Método BúsquedaPruebaLineal(A,n,clave)
pos  H(clave) //Genera dirección
Si (A[pos]=clave) entonces
retorna pos //valor hallado en pos
sino
posSgte  pos + 1
Mientras(posSgte<=n-1) y (A[posSgte]≠vacío) y (A[posSgte]≠clave)
y (pos≠posSgte) hacer
posSigte  posSigte + 1
Si (posSigte = n)entonces
posSigte  0
Fin Si
Fin Mientras
Si (A[posSgte]=vacío) o (pos=posSgte)entonces
Retornar -1 //valor no encontrado
sino
Retornar posSigte //valor hallado en posSigte
Fin Si
Fin Método
Reasignación por Prueba Cuadrática

 Es similar al anterior con la diferencia de que en este


método las direcciones alternativas se generarán
como:
D+1
D+4
D+9

D + i2
 Esta variación permite una mejor distribución de las
claves en colisión.
 Desventaja es que existe un agrupamiento alrededor
de ciertas claves y casillas no visitadas.
Reasignación por Prueba Cuadrática -
Ejemplo
 Sea A un arreglo de 10 elementos. Sean las claves 25,
43, 56, 35, 54, 13, 80, 104 y 55 asignadas según la
función hash H(K) = K mod 10
0 80
K H(K)
1 55
25 5
2
43 3
3 43
56 6
4 54
35 5
5 25
54 4
6 56
13 3
7 13
80 0
8 104
104 4
9 35
55 5
Reasignación por prueba cuadrática
Método BúsquedaPruebaCuadrática(A,n,clave)
pos  H(clave) //Genera dirección
Si (A[pos]=clave) entonces
retorna pos //valor hallado en pos
sino
i1, posSgte  pos + i*i, salir  falso
Mientras (A[posSgte]≠vacío) y (A[posSgte]≠clave) y
(salir = falso) hacer
i  i+1
posSigte  pos + i*i
Si (posSigte > n-1) entonces
i  0, posSigte  0, pos  0
Mientras (A[posSgte]≠vacío) y (A[posSgte]≠clave) y
(posSigte<=n-1) hacer
i  i+1
posSigte  pos + i*i
fin Mientras
salir  verdad
Fin Si
Fin Mientras
Reasignación por prueba cuadrática
Si (A[posSgte]=vacío)entonces
Retornar -1 //valor no encontrado
sino
Retornar posSigte //valor hallado en posSigte
Fin Si
Fin Método
Reasignación por Doble Dirección

 El método consiste en que cuando se detecta la


colisión, se debe generar otra dirección aplicando la
función hash a la dirección obtenida anteriormente.
 Se detiene el proceso cuando se halla el elemento, o
cuando se encuentra una posición vacía.
 La función hash que se aplique puede ser diferente
con respecto a la que se aplicó originalmente a la
clave.
 No existe ningún estudio que precise cuál función es la
mejor para emplear en el cálculo de las direcciones
sucesivas.
Reasignación por Doble Dirección-
Ejemplo
 Sea A un arreglo de 10 elementos. Sean las claves 25, 43, 56, 35,
54, 13, 80 y 104 asignadas según la función hash D = H(K) = K
mod 10 y H’(D) = (D+2) mod 10 para las direcciones sucesivas.

0 80 K H(K) H’(D) H’(D’) H’(D’’)


1 25 5 - - -
2 43 3 - - -
3 43 56 6 - - -
4 54 35 5 7 - -
5 25 54 4 - - -
6 56 13 3 5 7 9
7 35 80 0 - - -
8 104 104 4 6 8 -
9 13
Reasignación por Doble Dirección

Método BúsquedaDobleDirección(A,n,clave)
pos  H(clave) //Genera dirección
Si (A[pos]=clave) entonces
retorna pos //valor hallado en pos
sino
posSgte  H2(pos) //Genera dirección con segunda función Hash

Mientras(posSgte<=n-1) y (A[posSgte]≠vacío) y (A[posSgte]≠clave)


y (pos≠posSgte) hacer
posSgte  H2(posSigte)
Fin Mientras

Si (A[posSgte]=vacío) o (A[posSgte]≠clave)entonces
Retornar -1 //valor no encontrado
sino
Retornar posSigte //valor hallado en posSigte
Fin Si
Fin Método
Resolución de Colisiones por Arreglos
anidados
 Este método consiste en que cada elemento del
arreglo tenga otro arreglo en el cual se almacenen los
elementos colisionados.
 Aunque la solución parece sencilla, es ineficiente.
 Al trabajar con arreglos, se depende del espacio que
tienen asignados.
 Surge un problema: elegir el tamaño adecuado del
arreglo que permita un equilibrio entre el costo de
memoria y el número de valores colisionados que
puede almacenar.
Resolución de Colisiones por Arreglos
anidados - Ejemplo
 Sea A un arreglo de 10 elementos. Sean las claves 25, 43,
56, 35, 54, 13, 80 y 104 asignadas según la función hash
H(K) = K mod 10.

0 80 ••• K H(K)
1 25 5
2 43 3
3 43 13 56 6
4 54 104 35 5
5 25 35 54 4
6 56 13 3
7 80 0
8 104 4
9
Resolución de Colisiones por
Encadenamiento
 Consiste en que cada elemento del arreglo tenga un
apuntador a una lista enlazada.
 La lista se irá generando e irá almacenando los valores
colisionados a medida que se requiera. Es el método
más eficiente.
 Cualquiera que sea el número de colisiones, siempre se
puede tratar una más.
 La desventaja del método es que ocupa espacio
adicional al de la tabla y requiere el manejo de listas
enlazadas.
 Si las listas crecen demasiado se pierde la facilidad de
acceso directo del método hash.
Resolución de Colisiones por
Encadenamiento - Ejemplo
 Sea A un arreglo de 10 elementos. Sean las claves 25, 43,
56, 35, 54, 13, 80 y 104 asignadas según la función hash
H(K) = K mod 10.

0 80 K H(K)
1 25 5
2 43 3
3 43 13 N 56 6
4 54 104 N 35 5
5 25 35 N 54 4
6 56 13 3
7 80 0
8 104 4
9
Resolución de Colisiones por
Encadenamiento
Método BúsquedaEncadenamiento(A,n,clave)
pos  H(clave) //Genera dirección
Si (A[pos].dato = clave) entonces
Escribir “Clave hallada en “, pos //valor hallado en pos
sino
ptro  A[pos].sigte //ptro es una variable tipo puntero

Mientras(ptro ≠ NULL) y (ptro.dato ≠ clave) hacer


ptro  ptro.sigte
Fin Mientras

Si (ptro = NULL)entonces
Escribir “Clave no existe“ //valor no encontrado
sino
Escribir “Clave se encuentra en la lista“
Fin Si
Fin Método
Hash dinámico
Hash dinámico

 Las tablas hash se presentaron como una alternativa


hacia las estructuras tipo árbol ya que permitían el
almacenamiento de grandes volúmenes de
información y algoritmos eficientes para la
administración sobre estas estructuras (inserción,
eliminación y búsqueda).
 Sin embargo, presentan 2 grandes problemas:
1. No existen funciones hash perfectas que permitan asegurar
que por cada transformación de un elemento habrá una única
correspondencia en la clave que contiene este elemento.
2. Son estructuras estáticas que no pueden crecer ya que
necesitan un tamaño fijo para el funcionamiento de la
estructura.
Hash dinámico

 Para solucionar el segundo problema se implementa la


utilización de métodos totales y métodos parciales.
Convirtiendo la tabla hash en una estructura dinámica
capaz de almacenar un flujo de información y no una
cantidad fija de datos.
Métodos Totales – Expansiones totales
 El método de las expansiones totales consiste en realizar una
duplicación del tamaño del arreglo establecido para realizar la
tabla hash, esta expansión se ejecuta cuando se supera la
densidad de ocupación.
 Así si se tiene una tabla hash de tamaño N, al realizar la
expansión total se obtendrá una tabla hash de 2N, al realizar una
segunda expansión se obtendrá una tabla hash de 4N, al realizar
una tercera expansión se obtendrá una tabla hash de 8N y en
general el tamaño de la tabla para una i-ésima expansión se
define como aparece a continuación:

T = 2i * N
Dónde:
N: Tamaño de la Tabla.
i: Número de expansiones que se quieren realizar.
T: Nuevo tamaño de la Tabla.
Métodos Totales – Expansiones totales
 La densidad de ocupación se define como el cociente entre el
número de registros ocupados y el número de registros
disponibles; así se tiene que:
do = (ro/rd)*100
Dónde:
ro: Registros Ocupados.
rd: Registros Disponibles.
do: Densidad de Ocupación.

 Cada vez que se pretende insertar un elemento es necesario


calcular la densidad de ocupación, si se supera esta densidad se
procede a implementar la expansión. Al realizar cada de una de
las expansiones es necesario volver a implementar la función
hash para cada uno de los registros almacenados en la tabla y
volver a insertarlos de nuevo en la tabla.
Métodos Totales – Reducciones totales
 Este método surge como una consecuencia del método de
expansiones totales presentado anteriormente.
 En este método la densidad de ocupación disminuye de tal
manera que acepta una reducción del tamaño de la tabla hash a
la mitad. Así si se tiene una tabla hash de N, la primera reducción
dará como resultado la N/2, la segunda reducción dará como
resultado N/4, la tercera reducción dará N/8 y la i-ésima reducción
dará como resultado:

T = N / 2i
Dónde:
N: Tamaño de la Tabla.
i: Número de expansiones que se quieren realizar.
T: Nuevo tamaño de la Tabla.
Métodos Totales – Reducciones totales
 Para realizar una reducción la densidad de ocupación se debe
disminuir a un valor menor al rango establecido y los registros
se deben eliminar de tal manera que los registros resultantes
se puedan ingresar en una tabla hash que posea la mitad del
tamaño de la tabla original.
 Cada vez que se implementa una reducción es necesario
volver a utilizar la función hash con cada uno de los registros
almacenados.
Métodos Parciales – Expansiones
parciales
 El método de las expansiones parciales consiste en
incrementar en un 50% el tamaño del arreglo establecido para
realizar la tabla hash, esta expansión se ejecuta cuando se
supera la densidad de ocupación.
 Así si se tiene una tabla hash de tamaño N, al realizar la
expansión parcial se obtendrá una tabla hash de 1.5 N, al
realizar una segunda expansión se obtendrá una tabla hash de
2.25 N, al realizar una tercera expansión se obtendrá una tabla
hash de 3.375 N y en general el tamaño de la tabla para una i-
ésima expansión se define como:
T = (1.5) i * N
Dónde:
N: Tamaño de la Tabla.
i: Número de expansiones que se quieren realizar.
T: Nuevo tamaño de la Tabla.
Métodos Parciales – Expansiones
parciales
 Cada vez que se pretende insertar un elemento es necesario
calcular la densidad de ocupación, si se supera esta densidad
se procede a implementar la expansión.
 Al realizar cada de una de las expansiones es necesario volver
a implementar la función hash para cada uno de los registros
almacenados en la tabla hash y volver a insertarlos de nuevo
en la tabla.
Métodos Parciales – Reducciones
parciales
 Este método surge como una consecuencia del método de
expansiones parciales.
 En este método la densidad de ocupación disminuye de tal
manera que acepta una reducción del tamaño de la tabla hash
al 50%.
 Así si se tiene una tabla hash de N, la primera reducción dará
como resultado la 0.5 N, la segunda reducción dará como
resultado 0.25 N, la tercera reducción dará 0.125 N y la i-ésima
reducción dará como resultado:
T = (0.5)i * N
Dónde:
N: Tamaño de la Tabla.
i: Número de reducciones que se quieren realizar.
T: Nuevo tamaño de la Tabla.
Métodos Parciales – Reducciones
parciales
 Para realizar una reducción la densidad de ocupación debe
disminuir a un valor menor al rango establecido y los registros
se deben eliminar de tal manera que los registros resultantes
se puedan ingresar en una tabla hash que posea la mitad del
tamaño de la tabla original.
 Cada vez que se implementa una reducción es necesario
volver a utilizar la función hash con cada uno de los registros
almacenados.
Búsqueda externa por dispersión
Búsqueda externa por dispersión (Hash)

 Los archivos se organizan en cubetas


 Una cubeta contiene cero, uno o más bloques.
 Un bloque está formado por uno o más registros.

0 BLOQUE 1 BLOQUE 2
1
2 BLOQUE 1
3
4
5 BLOQUE 1 BLOQUE 2 BLOQUE 3
Directorio de cubetas
Búsqueda externa por dispersión (Hash)

 Funciones de dispersión (hash)


 Transforma la clave a una dirección que hace referencia
a una cubeta, en la cual se puede encontrar un registro.
 Si las claves fueran alfanuméricas, primero deberán
convertirse en numéricas, tratando de no perder
información.
 Las funciones módulo, cuadrado, plegamiento y
truncamiento vistas en la búsqueda interna son válidas
también en este caso.
 Es importante que la función distribuya
homogéneamente las claves entre los números de
cubetas disponibles.
Solución de colisiones

 Los bloques contienen un número fijo de registros


(uno o más registros).
 Las cubetas pueden no tener un límite de bloques que
pueden almacenar (encadenamiento), pero no
siempre es posible definir una estructura de este tipo.
 Para evitar las colisiones se debe elegir el tamaño
adecuado de cubetas y bloques.
 Si las cubetas se definen muy pequeñas el número de
colisiones aumenta.
 Si se definen muy grandes se pierde eficiencia de
almacenamiento y se pierden las ventajas del acceso
directo del método.
Solución de colisiones

Bloque
 Organizamos un archivo •
en cubetas que tienen un •

sólo bloque.
 La capacidad máxima de

Bloque
cada cubeta estará •

determinado por el •

tamaño del bloque


asociado con ella.

Bloque
 Una vez que se satura la •

cubeta, cualquier registro •
Directorio de
asignado a ella producirá cubetas
una colisión. •


Uso de áreas independientes para
colisiones
 Se definen áreas separadas (secundarias) de las
áreas primarias de almacenamiento, en las que se
almacenarán todos los registros que hayan
colisionado.
 El área de colisiones puede estar organizada como
un área común a todas las cubetas.
 Si se produce una colisión habrá que buscar a lo
largo del área de colisiones hasta encontrar el
elemento deseado.
Uso de áreas independientes para
colisiones



• •
• •

Directorio de
cubetas

Área de

colisiones
Área primaria de
almacenamiento
Uso de áreas independientes para
colisiones
 Otra forma de organizar el área de colisiones es
dividirla en bloques, asociando a cada uno de ellas a
uno del área primaria.
 Esta alternativa optimiza el tiempo de búsqueda en el
área de colisiones.
 Sin embargo, presenta el inconveniente de que estos
bloques podrían a su vez saturarse y ocasionar
nuevamente colisiones.
Uso de áreas independientes para
colisiones





• •
• •




Directorio de •

cubetas


Área de
Área primaria de colisiones
almacenamiento
Uso de áreas de colisiones entre los
bloques de almacenamiento primario
 Se definen áreas de colisiones entre los bloques de
almacenamiento primario.
 Es similar al método de reasignación en la búsqueda
interna.
 Una vez detectada una colisión en un bloque se debe
buscar en el área de colisiones inmediata a dicho
bloque.
 Si el elemento no se encuentra y el área de colisiones
está llena, se continuará la búsqueda a través de las
otras áreas de colisiones.
 El proceso termina cuando se encuentra el elemento o
cuando existen espacios vacíos en un bloque (elemento
no encontrado).
Uso de áreas de colisiones entre los
bloques de almacenamiento primario

Bloque

Bloque de colisiones

Bloque

Bloque de colisiones



Directorio de Área primaria de almacenamiento


cubetas con bloques para colisiones
Búsqueda externa dinámica

 Varía el número de cubetas en función de su densidad


de ocupación.
 Se comienza a trabajar con un número determinado de
cubetas y a medida que éstas se van llenando se
asignan nuevas cubetas al archivo.
 Existen dos formas:
 Expansiones totales
 Expansiones parciales
Expansiones Totales

 Consiste en duplicar el número de cubetas cuando


éstas superan la densidad de ocupación previamente
establecida.
N  2N  4N  • • •
 También se da en sentido contrario, es decir, si
disminuye la densidad de ocupación de las cubetas
entonces se reduce el número de éstas.
 Densidad de ocupación para expansión
Nro. Reg. ocupados / Nro. Reg. disponibles
 Densidad de ocupación para reducción
Nro. Reg. ocupados / Nro. de cubetas
Expansiones Totales - Ejemplo

Nro. cubetas = 2, dos registros por cubeta, densidad de ocupación


para expansión 80%, función hash:
H(clave) = clave MOD Nro. Cubetas
Se desean almacenar 42, 24, 15, 53

Clave H(clave)
42 0
Porcentaje de ocupación 0 42 15
24 0
para expansión: 75% 1 24
15 1
53 1

Después de insertar las 3 primeras claves


Expansiones Totales - Ejemplo

Cuando se quiere insertar 53, densidad de ocupación sería 100%.


Por lo tanto se duplican las cubetas a 2N = 4 y se reasignan los
registros

N=4
Clave H(clave)
Porcentaje de ocupación 0 24
para expansión: 50% 42 2
1 53
24 0
2 42
15 3
3 15
53 1

Después de insertar la clave 53


Expansiones Totales - Ejemplo

Clave H(clave)
Porcentaje de ocupación 0 24 12
para expansión: 75% 21 1
1 53 21
12 0
2 42
3 15

Luego de insertar las claves 21 y 12


Expansiones Totales - Ejemplo

Clave H(clave)
0 24
N=8 42 2
1
24 0
Porcentaje de ocupación 2 42
para expansión: 43.75%
15 7
3
53 5
4 12
21 5
5 53 21
12 4
6 14
14 6
7 15

Luego de insertar la clave 14


Expansiones Totales - Ejemplo

Clave H(clave)
42 2
N=8 24 0
0 24 128
15 7
1 49
53 5
Porcentaje de ocupación 2 42 18
para expansión: 68.75% 21 5
3
12 4
4 12
14 6
OBS: Si tratáramos de 5 53 21
insertar 192 se 18 2
produciría una colisión 6 14 22
49 1
192 MOD 8 = 0 7 15 23
128 0
22 6
23 7
Luego de insertar la clave 23
Expansiones Totales - Ejemplo

0 128
Clave H(clave)
1 49
42 10
N = 16 2 18
24 8
3 67
15 15
4
Porcentaje de ocupación 53 5
5 53 21
para expansión: 40.62% 21 5
6 22
12 12
7 23
Porcentaje de ocupación 14 14
8 24
para reducción: 81.25% 18 2
9
49 1
10 42
128 0
11
22 6
12 12
23 7
13
Luego de insertar la 67 3
14 14
clave 67 15 15
Expansiones Totales - Ejemplo

0 128
Clave H(clave)
1 49
42 10
N = 16 2 18
D.O. para expansión > 80% 24 8
3 67
D.O. para reducción < 80% 15 15
4
53 5
5 53 21
Porcentaje de ocupación
21 5
para expansión: 40.62% 6 22
12 12
7 23
Porcentaje de ocupación 14 14
8 24
para reducción: 81.25% 18 2
9
49 1
10 42
128 0
11
22 6
Si deseamos eliminar 53 12 12
23 7
D.O. Reducción 75% < 80% 13
67 3
14 14
15 15
Expansiones Totales - Ejemplo

0 128
Clave H(clave)
1 49
42 10
N = 16 2 18
D.O. para expansión > 80% 24 8
3 67
D.O. para reducción < 80% 15 15
4
53 5
5 53 21
Porcentaje de ocupación
21 5
para expansión: 40.62% 6 22
12 12
7 23
Porcentaje de ocupación 14 14
8 24
para reducción: 81.25% 18 2
9
49 1
10 42
128 0
11
22 6
Si deseamos eliminar 53 12 12
23 7
D.O. Reducción 75% < 80% 13
67 3
14 14
15 15
Expansiones Totales - Ejemplo

Clave H(clave)
42 2
N=8
D.O. para expansión > 80% 24 0
0 24 128
D.O. para reducción < 80% 15 7
1 49
21 5
2 42 18
Porcentaje de ocupación
12 4
para expansión: 68.75% 3 67
14 6
4 12
Porcentaje de ocupación 18 2
5 21
para reducción: 150% 49 1
6 14 22
128 0
7 15 23
22 6
23 7
67 3

Luego de eliminar 53
Expansiones Parciales

 Consiste en incrementar en 50% el número de


cubetas.
 Dos expansiones parciales equivalen a una total

2N 2N 2N

N  1.5N  2N  3N  4N  6N  8N • • •

2N 2N 2N
Expansiones Parciales - Ejemplo

Nro. cubetas = 2, dos registros por cubeta, densidad de ocupación


para expansión 80%, función hash:
H(clave) = clave MOD Nro. Cubetas
Se desean almacenar 42, 24, 15, 53

Clave H(clave)
42 0
Porcentaje de ocupación 0 42 15
24 0
para expansión: 75% 1 24
15 1
53 1

Después de insertar las 42, 24 y 15


Expansiones Parciales - Ejemplo

Cuando se quiere insertar 53, densidad de ocupación > 80%.


Por lo tanto se aumentan las cubetas a 1.5N = 3 y se reasignan los
registros

N=3 Clave H(clave)


Porcentaje de ocupación 0 42 24 15 42 0
para expansión: 66.66% 24 0
1
2 53 15 0
En la cubeta 0 se tiene
una colisión, mientras 53 2
que la 1 permanece
vacía

Después de insertar la clave 53


Expansiones Parciales - Ejemplo

N=4 Clave H(clave)


Porcentaje de ocupación 0 24 42 2
para expansión: 62.5% 24 0
1 53 21
2 42 15 3
3 15 53 1
21 1

Después de insertar la clave 21


Expansiones Parciales - Ejemplo

N=4 Clave H(clave)


Porcentaje de ocupación 0 24 12 42 2
para expansión: 75% 24 0
1 53 21
2 42 15 3
3 15 53 1
21 1
12 0

Después de insertar la clave 12


Expansiones Parciales - Ejemplo

N=6

Porcentaje de ocupación Clave H(clave)


para expansión: 75% 42 0
24 0
0 42 24 12 18
15 3
1 49
53 5
2 14
21 3
3 15 21
12 0
4
14 2
5 53
18 0
49 1

Luego de expandir e insertar las claves 14, 18 y 49


Expansiones Parciales - Ejemplo

N=8 Clave H(clave)


42 2
Porcentaje de ocupación
para expansión: 75% 24 0
15 7
0 24 128 53 5
1 49 21 5
2 42 18 12 4
3 14 6
4 12 18 2
5 53 21 49 1
6 14 22 128 0
7 15 23 22 6
23 7

Luego de expandir e insertar las claves 128, 22 y 23


Expansiones Parciales - Ejemplo

N=8 Clave H(clave)


42 2
Porcentaje de ocupación
para expansión: 75% 24 0
15 7
0 24 128 53 5
1 49 21 5
2 42 18 12 4
3 14 6
4 12 18 2
5 53 21 49 1
6 14 22 128 0
7 15 23 22 6
23 7

Luego de expandir e insertar las claves 128, 22 y 23


Tarea

 Implemente los métodos de búsqueda, inserción y


eliminación en un arreglo, resolviendo las colisiones
mediante:
 Reasignación por prueba cuadrática.
 Reasignación por doble dirección
 Por arreglos anidados
 Por encadenamiento

Nota: Desarrolle una aplicación para cada caso

También podría gustarte