[C con Clase] administrador tabla hash con direccionamiento abierto
Steven R. Davidson
vze266ft en verizon.net
Mar Mar 25 11:47:06 CET 2008
Hola Germán,
German Ponce wrote:
> me gustaria saber si hay dentro de la pagina cconclase o en otro lugar
> un ejemplo de lo que tiene que tener una tabla hash con direccionamiento
> abierto asi como la construccion de adminstrador de tablas hash,
> cualquier ayuda sera bien recibida .
>
> el motivo de esta consulta es para construir la tabla de simbolos de un
> compilador
>
Direccionamiento abierto o "háshing" cerrado se basa en crear una tabla
hash cuyos elementos contienen la información interesada. Típicamente,
usamos un cálculo sencillo para "hashear" los datos, como suele ser el
módulo de la división. Por ejemplo,
h(k) = k mod m, donde
'k' es la clave (o dato numérico), y
'm' es la cantidad máxima de elementos en nuestra tabla. Uno suele usar
un valor que sea una potencia de dos para 'm'.
Por ejemplo, tenemos el cálculo:
h(k) = k mod 16, y
los siguientes valores:
45, 32, 602, 1031, y 923
Aplicamos la función 'h(k)' a cada valor, obteniendo:
h(45) = 45 mod 16 = 13
h(32) = 32 mod 16 = 0
h(602) = 602 mod 16 = 10
h(1031) = 1031 mod 16 = 7
h(923) = 923 mod 16 = 11
La tabla hash sería la siguiente:
0 => 32
1 => --
2 => --
3 => --
4 => --
5 => --
6 => --
7 => 1031
8 => --
9 => --
10 => 602
11 => 923
12 => --
13 => 45
14 => --
15 => --
Sin embargo, tenemos un problema si quisiéramos agregar el valor de
1024, ya que h(1024) = 0. Como la tabla hash ya contiene un valor en el
índice 0, el número 32, nos encontramos con una colisión.
Para resolver colisiones en el direccionamiento abierto, tenemos algunos
métodos que podemos implementar. Los métodos más populares se basan en
modificar la función 'h(k)' para buscar otro "hueco" en la tabla. He
aquí los más populares:
* Investigación o Búsqueda lineal (linear probing)
Modificamos la función agregando un desplazamiento (lineal) al cálculo;
esto es,
h(k,i) = (k + i) mod m, donde i=0,1,2,...
Inicialmente, aplicaríamos h(k,0) que es igual a la función original de
h(k). Si ésta no da el resultado que queremos, entonces probamos con
i=1. Si tampoco da resultado, entonces con i=1, i=2, i=3, etcétera hasta
que algún valor de 'i' dé el resultado esperado. Si damos la vuelta
completa: h(k,0) = h(k,i) entonces abandomos el intento, sin poder
realizar el háshing.
Usando el ejemplo anterior, ingresamos 1024 de la siguiente manera:
h(1024) = 1024 mod 16 = 0 => colisión
h(1024,1) = 1025 mod 16 = 1 => sin colisiones
* Investigación o Búsqueda cuadrática (quadratic probing)
El método anterior sufre de un problema importante: agrupamiento. Los
valores se agruparán linealmente, si hubo colisiones. Para aminorar este
problema, usamos otro cálculo:
h(k,i) = (k + a*i + b*i^2) mod m, donde i=0,1,2,... y b != 0
Usando el ejemplo, agregamos 1024 así:
h(k,i) = (k + i + 3*i^2) mod 16, donde a=1 y b=3.
Probanod con h(1024,0) sabemos que existe una colisión, por lo que
pasamos a i=1:
h(1024,1) = (1024 + 1 + 3*1) mod 16 = 4
Si este índice también provocase una colisión, entonces pasaríamos a
probar con i=2:
h(1024,2) = (1024 + 2 + 3*4) mod 16 = 14
* Doble Háshing (double hashing)
Aquí básicamente usamos dos funciones de háshing. El ejemplo popular
para hacer esto es,
h(k,i) = (f(k), + i*g(k)) mod m.
Ahora bien, para que este método sea práctico, el valor de 'g(k)' debe
ser relativamente primo a 'm'. Podemos dejar que 'm' sea una potencia de
dos y que 'g(k)' sea impar. Por ejemplo,
f(k) = k mod m,
g(k) = (2*k+1) mod m'.
Usando nuestro ejemplo, colocamos 1024 con m=16 y m'=15 así:
h(1024,1) = (f(1024) + g(1024)) mod 16.
f(1024) = 1024 mod 16 = 0
g(1024) = (2*1024+1) mod 15 = 9
Por lo que tenemos,
h(1024,1) = (0 + 9) mod 16 = 9
Otra forma es escoger números primos para los módulos. Por ejemplo,
f(k) = k mod m,
g(k) = 1 + (k mod m'),
Podríamos escoger m=13 y m'=11.
Espero que todo esto te ayude.
Steven
Más información sobre la lista de distribución Cconclase