Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Funciones de dispersión
Resolución de colisiones. Direccionamiento abierto
Resolución de colisiones. Mediante encadenamiento
Dispersión extensible. Basada en directorio
Dispersión extensible. Basada en división lineal
Implementación en Java de un contenedor que usa dispersión que resuelve las c
olisiones por direccionamiento abierto con prueba lineal
Implementación en Java de un contenedor que usa dispersión que resuelve las c
olisiones por encadenamiento con cadenas separadas
Implementación en Java de un contenedor persistente que usa dispersión exten
sible basada en directorio
Contenedores
Muchas operaciones dependen de la localización de un
elemento.
Los mejores algoritmos de búsqueda son de O(log n).
Objetivo:
• Conocer inmediatamente dónde está o debe ir un
dato
Operaciones con coste de orden 1.
Dispersión
Conjunto de valores de claves Espacio de almacenamiento
y Función de dispersión
z
Colisión
Conjunto de valores de claves Espacio de almacenamiento
x Colisión
y
Función de dispersión
z
Técnicas de dispersión
Funciones de dispersión
Inicio
Pseudoclave
Se requiere un representación numérica de la clave.
Se puede basar en la representación interna de la clave.
En las ristras se usa valor de codificación de los caracteres
(ANSI, UNICODE, UTF-8, etc.).
En claves compuestas hay que formar la pseudoclave
haciendo que participen todas las partes.
Función de dispersión
Necesidad de adaptar la pseudoclave a la tabla.
Método de la división o del módulo
Método del cuadrado central
Método plegable
Análisis de dígitos
Métodos dependientes de la longitud
Función de dispersión
Método de la división o del módulo.
Es una de las funciones de dispersión más
antiguas y con mayor aceptación.
Se define como:
H(x) = (x mod LTabla)
Por ejemplo, si x=35 y LTabla=11 entonces:
H(35) = 35 mod 11 = 2
Función de dispersión
Método del cuadrado central.
Cada valor de la pseudoclave se multiplica por sí
mismo.
Se obtiene una dirección seleccionando un número
apropiado de bits o dígitos hacia la mitad del
cuadrado.
Ejemplo: 123456. El cuadrado es 15241383936. Se eligen
las posiciones de la 5 a la 7; así, la dirección dada sería
138 de 15241383936.
Función de dispersión
Método plegable.
Consiste en dividir la pseudoclave en un cierto
número de partes.
Cada una de las cuales tiene la misma longitud que la
dirección requerida, excepto quizá la última.
Se suman ignorando el acarreo final.
Para el valor de pseudoclave 356942781 se divide en
tres partes —356, 942 y 781— que se suman y dan 079.
Si los valores se toman en forma binaria, se puede
sustituir la suma por un o-exclusivo.
Una aplicación típica permite reducir a una palabra
claves que ocupan más de una.
Función de dispersión
Análisis de dígitos.
típica
Función de dispersión
Métodos dependientes de la longitud.
x Colisión
y
Función de dispersión
z
Resolución de colisiones mediante
direccionamiento abierto
Sitúa las colisiones en algún lugar de la tabla de dispersión
distinto del que les correspondía.
Es necesario explorar la tabla de dispersión hasta encontrar
una posición vacía.
La exploración debe ser eficiente y repetible.
Debe ser repetible para poder localizar el registro.
La secuencia de búsqueda se puede determinar mediante
la expresión:
pk(x) = (H(x) + f(k)) mod LTabla
Donde:
x es la clave a insertar
pk(x) es la posición a examinar en el k-ésimo intento
f(k) es una función que define la estrategia de búsqueda
Resolución de colisiones mediante
direccionamiento abierto
Prueba lineal: f(k) = k
pk(x) = (H(x) + k) mod LTabla
Es decir, si a una clave le corresponde una dirección d,
se busca la primera libre en la secuencia:
d, d+1,…,Ltabla, 1, 2,…, d-1
La prueba lineal es razonablemente buena cuando la
tabla no está demasiado llena.
Los resultados son aceptables para un factor de carga
inferior a 0.8
El factor de carga es la relación entre el número de datos
almacenados y el tamaño de la tabla.
Prueba lineal
Posición Clave Posiciones examinadas
Clave H(Clave)
0 Barcelona
Valencia
Lérida 0 10, 0
9,
Barcelona 0
1 Lérida
Valencia 0, 10,
9, 1 0, 1
Cádiz 6
2 Madrid
Valencia 2
9, 10, 0, 1, 2
Córdoba 6
3 Valencia 9, 10, 0, 1, 2, 3
Granada 6
4
Lérida 0 5
Madrid 2 6 Cádiz
Córdoba
´Málaga
Granada
Sevilla 6
Málaga 6 7 Córdoba
Málaga
Granada
Sevilla 6, 7
Sevilla 6 8 Granada
Málaga
Sevilla 6, 7,
6, 7, 8
8
Valencia 9 9 Valencia
Málaga
Sevilla 9
6, 7, 8, 9
10 Sevilla
Valencia 6, 10
9, 7, 8, 9, 10
Resolución de colisiones mediante
direccionamiento abierto
Prueba aleatoria: f(k) = k*C
pk(x) = (H(x) + k * C) mod LTabla
Donde C es un valor mayor que 1 y sin
divisores comunes con LTabla.
Independiza la secuencia de prueba de la
secuencia física de posiciones en la tabla.
Ejemplo: Para LTabla = 11 y C = 3
Secuencia de posiciones a probar desde 5:
5, 8, 0, 3, 6, 9, 1, 4, 7, 10, 2
Resolución de colisiones mediante
direccionamiento abierto
Doble dispersión: f(k) = k*H2(x)
pk(x) = (H1(x) + k * H2(x)) mod LTabla
Usa como desplazamiento un valor dependiente de la clave: otra
función de dispersión H2(x)
H2(x) debe ser independiente de H1(x) para que dos claves que
colisionen tengan secuencias de prueba diferentes
Una posibilidad para LTabla primo podría ser:
H1 = x mod LTabla
H2 = (x mod (LTabla - 2)) + 1
Por ejemplo para LTabla=11:
Con x=75: H1(75)=9 y H2(75)=4 y la secuencia de prueba es:
9, 2, 6, 10, 3, 7, 0, 4, 8, 1, 5
Con x=42: H1(42)=9 y H2(42)=7 y la secuencia de prueba es:
9, 5, 1, 8, 4, 0, 7, 3, 10, 6, 2
Resolución de colisiones mediante
direccionamiento abierto
Problemas
Las listas de sobrecarga acaban con posiciones con marca de libre.
Tiene que haber muchos con marca de libre.
En la secuencia de búsqueda se entremezclan claves con diferentes valores de H.
La extracción es difícil: No basta con marcar el lugar como vacío.
O bien cada posición, además de tener la marca de libre u ocupado, debe admitir la de
liberado —cuando es extraído.
Las posiciones que se marcan como liberado, se consideran:
Libres para las inserciones
Hueco
Zona libre: Si
H(Candidato) cae
en esta zona, puede
ocupar el hueco Inicio
Fin
Zona prohibida: Si
H(Candidato) cae en
esta zona, no puede
ocupar el hueco
Candidato
a ocupar Hueco
Resolución de colisiones mediante
direccionamiento abierto
Extracción con desplazamiento de la secuencia de colisiones
Candidato
Zona prohibida: Si
H(Candidato) cae
en esta zona no Inicio
puede ocupar el
hueco
Fin
Zona libre: Si
H(Candidato) cae
en esta zona, puede
Hueco ocupar el hueco
Técnicas de dispersión
Resolución de colisiones. Mediante encadenamiento
Inicio
Encadenamiento mediante el método de las
cadenas fundidas
Se forma una lista encadenada de registros con claves
sinónimas
En lugar de reproducir en la búsqueda la secuencia de
comparaciones que se usó en la inserción.
Permite solucionar sin desplazamiento las posiciones
liberadas durante la extracción.
Se mantiene el problema de la mezcla de listas de
sinónimos diferentes.
Degenera con factores de carga altos.
Cadenas fundidas
Posición Clave Siguiente
Clave H(Clave)
0 Valencia
Barcelona
Lérida -1 (último)
1
Barcelona 0
1 Valencia
Lérida -1 (último)
Cádiz 6
2 Madrid
Valencia -1 (último)
Córdoba 6
3 Valencia -1 (último)
Granada 6
4
Lérida 0 5
Madrid 2 6 Granada
Córdoba
Málaga
Sevilla
Cádiz 7
-1 (último)
Málaga 6 7 Córdoba
Sevilla
Málaga
Granada -1 (último)
8
Sevilla 6 8 Granada
Sevilla
Málaga -1 (último)
9
Valencia 9 9 Sevilla
Valencia
Málaga 10
-1 (último)
10 Sevilla
Valencia -1 (último)
3
Resolución de colisiones mediante
encadenamiento de cadenas separadas
Los registros con igual valor de función de
dispersión se encadenan en una lista.
Las cadenas se forman en un área de
sobrecarga separada.
La capacidad de almacenamiento está limitada
por la suma de la tabla más el área de
sobrecarga.
Se conoce también como dispersión abierta,
frente a dispersión cerrada.
Resolución de colisiones mediante cadenas
separadas
Clave H(Clave)
Barcelona 0 0 Barcelona Lérida
1
Cádiz 6
2 Madrid
Córdoba 6
3
Granada 6 4
Lérida 0 5
6 Cádiz Granada
Córdoba
Málaga
Sevilla Málaga
Granada
Córdoba
Madrid 2
7
Málaga 6
8
Sevilla 6 9 Valencia Granada
Córdoba Córdoba
Valencia 9 10
Madrid
12
10101010
11011011 Se inserta 11100011 y 10101101
10101101
11110000
10101010 2
11100011
10101101 11011011
11110000
11100011
Página sobrecargada
Dispersión extensible basada en directorio
En general, la recuperación de un registro requiere dos
accesos externos
Uno para obtener la entrada del directorio
Otro para acceder a la página correspondiente
En algunos casos será posible mantener el directorio
completo en memoria principal.
La recuperación sólo requiere un acceso externo.
Las páginas se pueden organizar internamente como
tablas de dispersión de tamaño fijo para eludir la
búsqueda secuencial.
Técnicas de dispersión
Dispersión extensible. Basada en división lineal
Inicio
Dispersión extensible basada en división
lineal
La dispersión lineal consigue que la tabla pueda
incrementar su tamaño con un mínimo esfuerzo.
Se basa en el uso de dos funciones de dispersión.
La tabla está dividida en dos zonas.
En cada zona se aplica una función de dispersión.
Dispersión extensible basada en división
lineal
La dispersión lineal está pensada para ser
usada en disco.
Se tiene la tabla que está compuesta de celdas
con cierta capacidad.
La tabla puede crecer por el final.
Se tiene una zona de sobrecarga donde se
mantiene una lista de celdas para absorber la
sobrecarga en las celdas de la tabla
Dispersión extensible basada en división
lineal
Las funciones de dispersión usadas se definen
como:
Hi(K): S [0 .. 2i*N-1], donde N es el
número inicial de páginas debe ser potencia
de 2
Siempre se usan dos funciones consecutivas.
Las funciones deben cumplir que
Hi+1(K) = Hi(K) + (2i ó 0)
Dispersión extensible basada en división
lineal
La tabla está dividida en dos zonas por el
llamado puntero de división, pd.
Para usar una función u otra se emplea el
siguiente criterio
cc <- Hi(K)
si cc < pd entonces
cc <- Hi+1(K)
fin si
... ...
Última celda
Celdas de sobrecarga
Dispersión extensible basada en división
lineal
El crecimiento de la tabla se produce
incrementando el puntero de división.
A los datos en la entrada pd se accedía
mediante Hi, tras la división habrá que acceder
mediante Hi+1.
Los datos se reparten entre las entradas pd y
pd+2i*N aplicando Hi+1
Dispersión extensible basada en división
lineal
La tabla aumenta siempre según el puntero de
división, sin importar donde se produzcan las
inserciones.
Los criterios para aplicar una división pueden
ser variados.
Por ejemplo: Aplicar la división cuando se cree
una nueva celda de sobrecarga.
Ejemplo
Se inserta 10100100, 11010101, 11001010, Insertar 01010101 implica
00000011, 01110000, 11010001 Sobrecargar la segunda celda y
Dividir la primera
pd pd pd pd
00000 001
01 010
10 011
11 100 101 110 111
00011000
10100100 11010101 11001010 00000011 10100100 11010101 10001110 11110111
01110000 11010001 10101110 11110111 00111100 01010101 10101110 11000111
}
buscar
Devuelve la posición de la clave o
private int buscar(Object e) {
int actual = disp(e);
el primer sitio libre donde situarla
int límite = actual;
// La clave se busca a partir de la posición que le corresponde y se continúa
//hasta encontrarla, hallar una posición vacía o volver al punto de partida
do {
if (!ocupados[actual]) return actual;
else
if (elementos[actual].hashCode() == e.hashCode()) return actual;
actual = (actual + 1) % elementos.length;
} while (actual != límite);
return -1; Si la posición que devuelve está
} ocupada debe contener la clave e
public TablaDispersión() {
this(51);
}
...
Clase DispersiónExtensible
...
int log2(long dato) { Calcula el logaritmo entero en base 2:
int res = 0; La posición del bit más significativo
for (int i = 1; i < 32; i++)
if (((dato >> i) & 1) == 1) res = i;
return res;
}
protected int dispersión(int profundidad, Almacenable e) {
int pse = e.hashCode();
int res = 0;
for (int i = 0; i < profundidad; i++) { Función de dispersión: Devuelve los
res <<= 1;
profundidad dígitos menos significativos
de la pseudoclave en orden inverso
if ((pse & 1) == 1) res |= 1;
pse >>= 1;
}
return res;
}
Página leerPágina(int dir) {
Página página = new Página(); Lee la página de datos de la posición dir
página.deByte(páginas.leer(dir));
if (página.dirección != dir)
throw new Fichero.ExcepcionFichero("Error al leer página");
return página;
}
...
Clase DispersiónExtensible
...
void escribirPágina(Página página) { Escribe la página en el fichero de datos
páginas.escribir(página.aByte(), página.dirección); en la posición que le corresponde
}
Página() {
dirección = -1; La clase Página permite el tratamiento
profundidad = 0;
numEle = 0;
de las páginas del fichero de datos
elementos = new byte[TDC][];
}
...
DispersiónExtensible: Clase Página
...
byte[] aByte() { Devuelve un byte[] con el
int tam = tamaño();
contenido de la página actual
byte[] res = new byte[tam];
int pos = 0;
pos = Conversor.añade(res, Conversor.aByte(dirección), pos);
pos = Conversor.añade(res, Conversor.aByte(profundidad), pos);
pos = Conversor.añade(res, Conversor.aByte(numEle), pos);
for (int i = 0; i < numEle; i++)
pos = Conversor.añade(res, elementos[i], pos);
return res;
} Restaura el objeto actual a partir
de un byte[] obtenido con aByte
void deByte(byte[] datos) {
int lbi=Conversor.INTBYTES; //longitud en bytes de los enteros
dirección = Conversor.aInt(Conversor.toma(datos, 0, lbi));
profundidad = Conversor.aInt(Conversor.toma(datos, lbi, lbi));
numEle = Conversor.aInt(Conversor.toma(datos, lbi * 2, lbi));
for (int i = 0; i < numEle; i++){
int pos = lbi * 3 + i * tamañoDatos;
elementos[i] = Conversor.toma(datos, pos, tamañoDatos);
}
}
}
Operación de la interfaz ContenedorPersistente que crea el directorio y el