Está en la página 1de 41

+ Grado en

Ingeniería
Tema 4 Informática

Diccionarios Estructuras
de Datos II
2018/19

Departamento de Tecnologías de la Información


Universidad de Huelva
+ 2

Diccionarios
Objetivos
Conocer el TAD Diccionario como contenedor asociativo
Conocer la tabla dispersa como estructura eficiente de implementación de diccionarios
Conocer las funciones de dispersión, así como los métodos de gestión de colisiones
más habituales

Contenidos
4.1 Conceptos
4.2 Especificación algebraica
4.3 Implementación
4.4 Implementación de diccionarios usando un ARN
4.5 Tablas dispersas
4.5.1 Conceptos
4.5.2 Funciones de dispersión
4.5.3 Resolución de colisiones
4.6 Implementación de diccionarios usando una tabla dispersa

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 3

Diccionarios

Duración
3 clases

Bibliografía
Data Structures and Algorithms in C++
Autores: Michael T. Goodrich, Roberto Tamassia, David M. Mount
Editorial: John Wiley & Sons, Inc.
Año: 2004
Págs. 363 – 410
Fundamentos de Estructuras de Datos. Soluciones en Ada, Java y C++
Autores: Zenón J. Hernández Figueroa y otros
Editorial : Thomson, 2005
Págs. 47 – 135

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+
4.1 Conceptos

4
+ 5

Conceptos

El diccionario permite representar una aplicación entre dos conjuntos cuando no


es posible describirla mediante un algoritmo

• En caso contrario, sería suficiente con definir la función correspondiente

Los valores del conjunto origen o dominio de la aplicación se denominan claves

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 6

Conceptos

Con los diccionarios se consiguen, en condiciones adecuadas, rendimientos


independientes del número de elementos

La idea fundamental es hacer corresponder a cada clave (mediante


operaciones aritméticas), una posición del espacio de almacenamiento, que
deber cumplir que sea:

Concreta
Independiente de qué otras claves estén almacenadas

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 7

Conceptos

El TAD de las funciones f: Dclaves Dvalores, donde Dclaves representa el conjunto de claves y
Dvalores el conjunto de valores, es conocido en el ámbito de las estructuras de datos, con el
nombre de diccionario (también conocido como tipo asociativo, funcional o tabla)
Un diccionario se define como un conjunto de pares (c, v), donde c se denomina clave y v
representa el valor asociado a la clave. Supondremos que en este conjunto no puede
haber dos pares con la misma clave, es decir, las claves son únicas
Las principales operaciones que suelen realizarse sobre diccionarios son:
crear una diccionario vacío
insertar un nuevo par (c, v)
comprobar la existencia de una clave en el diccionario
consultar el valor v asociado a una clave c
modificar el valor v asociado a una clave c
borrar un par (c, v)
comprobar si el diccionario está vacío

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 8

Conceptos

Muchas aplicaciones usan conjuntos de datos, que pueden variar en tiempo de


ejecución

Cada dato tiene una clave y, asociado a ella, se guardan una serie de valores

Las operaciones de consulta de datos se realizan por clave

Ejemplos de aplicaciones:
Agenda electrónica
Diccionario de sinónimos
Compiladores
etc.

Normalmente, no son frecuentes las operaciones de unión, intersección o diferencia


de diccionarios. Las operaciones mas frecuentes son las inserciones, consultas y
eliminaciones en diccionarios

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+
4.2 Especificación
Algebraica

9
+ 10

Especificación Algebracica
espec Diccionarios
usa booleanos

parámetro formal
géneros clave, valor
operaciones
_ == _ : clave clave booleano
fpf

género diccionario

operaciones
dVacío: diccionario
asignar: diccionario clave valor diccionario {inserta/modifica}
esVacío?: diccionario booleano
está?: diccionario clave booleano
parcial observar: diccionario clave valor
eliminar: diccionario clave diccionario

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 11

Especificación Algebracica
dominios de definición d: diccionario; c: clave
observar(d, c) está definido sólo si está?(d, c)

ecuaciones d: diccionario; c, c1,c2: clave; v, v1,v2: valor

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+
4.3 Implementación

12
+ Implementación 13

Un Par es un objeto con dos atributo de tipo genérico: clave y valor

template <typename C, typename V>


class Par {
public:
Par(const C& c, const V& v);
const C& getClave() const;
const V& getValor() const;
private:
C clave;
V valor;
};

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 14

Implementación

Interfaz informal de la clase Diccionario:

template <typename C, typename V>


class Diccionario {
public:
Diccionario();
void asignar(const Par<C,V>& p);
bool observar(const C& c, V& v);
void eliminar(const C& c);
~Diccionario();
};

asignar inserta/modifica el par <c,v> pasado por parámetro


observar busca la clave c en el diccionario y si la encuentra devuelve verdad y
proporciona en v su valor asociado. En caso contrario devuelve falso.
eliminar borra del diccionario el par <c,v> asociado a la clave c proporcionada

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


4.4 Implementación de
+
diccionarios usando un
ARN

15
+ 16

Implementación usando ARN

En este apartado presentamos una implementación utilizando un árbol rojo-negro


(ARN)

template <typename C, typename V>


class Diccionario {
public:
Diccionario();
void asignar(const Par<C,V>& p);
bool observar(const C& c, V& v);
void eliminar(const C& c);
~Diccionario();
private:
ARN< Par<C, V> > d;
};

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 17

Implementación usando ARN

Eficiencia de las operaciones

Operación ARN

Diccionario

asignar

observar

eliminar

~Diccionario

n: número elementos del diccionario

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+
4.5 Tablas Dispersas

18
+ 19

Conceptos

Si el conjunto de las claves está formado por un número relativamente pequeño de


números naturales (cercanos entre ellos) y no hay dos elementos con la misma clave, se
puede utilizar una representación mediante una tabla (tabla de acceso directo)
Si las claves no son numéricas o no se cumple lo anterior, debería existir una función
inyectiva1 que transforme cada clave en un número (índice) comprendido en el subrango
[0..max-1] de la tabla
T
valor 1 0

f: Dclaves 0 .. max-1 valor 2


claves

c1
c10 valor 6

c6
valor 8
c8

valor 10
1 f: X Y es inyectiva si y solo si: …
max
max-1
x1, x2 ∈ X tal que f(x1) =f(x2) x1=x2
+ 20

Conceptos

Todas las operaciones realizadas con este tipo de representación son de orden O(1)

En contraposición, los principales inconvenientes son:

desaprovechamiento de la memoria si el número de elementos almacenados


en la tabla T es pequeño en relación con el número posible de claves

es difícil encontrar funciones inyectivas que transformen claves en índices

Una alternativa a las tablas de acceso directo son las tablas dispersas o tablas hash,
que consiguen, aproximadamente, un coste de orden constante para todas las
operaciones
+ 21

Conceptos
Una tabla dispersa es una estructura similar a la tabla de acceso directo

En lugar de utilizar la clave para indexar directamente sobre la tabla, el índice es


calculado a partir de la clave utilizando una función de dispersión (h)

h(c24) 0
h: Dclaves 0.. max-1 valor24
valor5
h(c5)

claves
h(c3)
c78 función de valor3
c5 dispersión (h)
c24
h(c78) valor78
c3
índices

max-1
+ 22

Conceptos

No es necesario que la función h sea inyectiva. Se dividen las claves en n clases de


equivalencia. En cada clase se encuentran las claves que al aplicarles la función h
devuelven el mismo valor (posición en la tabla)

h(ci) es el índice o valor de dispersión calculado por h al suministrarle la clave ci

Se dice que ci se dispersa en la posición h(ci) de la tabla dispersa T

De esta forma se soluciona el problema de las claves no numéricas o números muy


grandes

Uno de los aspectos fundamentales en las tablas dispersas consiste en realizar una buena
elección de la función h

Esta función debe distribuir las claves esperadas de la manera más uniforme posible en el
rango 0..max-1, de forma que la probabilidad de que 2 claves distintas (c1 ≠ c2) obtengan el
mismo valor de h (h(c1) = h(c2)) sea lo más baja posible
+ 23

Conceptos

Para definir una tabla dispersa, el programador debe tomar 2 decisiones


importantes

1. Elegir la función h. Como la función no es inyectiva es posible que una


posición calculada para una clave c ya esté ocupada colisión

2. Seleccionar un método para resolver las colisiones

a. Dispersión abierta. Los elementos que colisionan se sitúan en una lista


a partir de la posición calculada

b. Dispersión cerrada. Los elementos que colisionan se sitúan en la


propia tabla. Hace falta un algoritmo de recolocación de elementos
+ 24

Funciones de dispersión
Características de las funciones de dispersión

Las características que debería tener una buena función de dispersión son:

1. Rapidez de cálculo

2. Exhaustividad: Todo índice o valor de dispersión h(ci) debe tener asociado,


como mínimo, una clave

3. Distribución uniforme: Todos los valores de dispersión deben tener,


aproximadamente, el mismo número de claves asociadas
+ 25

Funciones de dispersión
Traducción de cadenas a enteros

Suma de los caracteres


• A cada carácter se le calcula su valor decimal
• Se suman los números obtenidos
c = “pérez” num (c) = dec (‘p’) + dec (‘é’) + dec (‘r’) + dec (‘e’) + dec (‘z’) = 112 + 130 + 114 + 101 + 122 = 579
Si c = “abc”, cualquier combinación de los caracteres que la forman tendrán el mismo valor decimal asociado:
num (c) = dec (‘a’) + dec (‘b’) + dec ('c’) = 97 + 98 + 99 = 294

Suma ponderada de los caracteres


• La cadena se trata como un entero en base n (n ≡ número de caracteres del código)
c = “pérez” {base=256 nº caracteres}
num (c) = dec (‘p’) * 2564 + dec (‘é’) * 2563 + dec (‘r’) * 2562 + dec (‘e’) * 256 + dec (‘z’) = “número muy grande”

Problema: Con las claves no numéricas o las claves muy grandes Ajuste en Intervalo

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 26

Funciones de dispersión
Funciones que obtienen valores en un intervalo (1/2)

División

Se calcula el resto de dividir el número entre max (max ≡ tamaño de la tabla)

h(c) = c mod max → (Valor entre 0 y max-1)


Puede funcionar mal, por ejemplo si max = 10 y casi todas las claves son múltiplos de
10, habrá muchas colisiones ya que para casi todas las claves h(c) = 0
NOTA: el max más apropiado es un número primo
(Es mucho más difícil tener claves que sean multiplos de números primos)

Método del cuadrado

Consiste en calcular el cuadrado de la clave c. El índice se obtiene de los


dígitos de c2 que ocupan una determinada posición

265 70225 h (265) = 22


1340 1795600 h (1340) = 956
777 603729 h (777) = 372

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 27

Funciones de dispersión
Funciones que obtienen valores en un intervalo (2/2)

Plegamiento

• Consiste en dividir la clave c en partes de igual número de dígitos (la última puede
tener menos dígitos) y operar con ellas, tomando como índice los dígitos menos
significativos del resultado
• La operación entre las partes puede hacerse por medio de sumas o multiplicaciones

h (152635) = 15 + 26 + 35 = 76

h (934058) = 93 + 40 + 58 = 1 91 h (934058) = 91

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 28

Funciones de dispersión
Clases Universales de Funciones de Dispersión

• A pesar de que las funciones de dispersión pretenden conseguir una distribución


uniforme de los datos, en la práctica puede ocurrir que los datos presenten un patrón
que haga que se concentren en el diccionario.
• La dispersión universal es una técnica que permite elegir aleatoriamente una función
de dispersión de forma que se obtenga un rendimiento promedio.

Ejemplo:
• Sea p un número primo mayor o igual que C (cardinal del espacio de claves), y sean i
y j dos enteros menores que p. Se define hij: C 1..max-1, como:
hij(x)=((ix + j) mod p) mod max
• De forma que F= {hij | 1≤ i < p y 0 ≤ j < p}, es una clase universal de funciones de
dispersión de C en 1..max.
• Para seleccionar aleatoriamente una función de F sólo es necesario elegir dos enteros
(i, j) menores que p.

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 29

Resolución de Colisiones
Dispersión abierta: por encadenamiento

Todos los pares (clave, valor) cuya clave es asignada por la función de dispersión h a una
misma posición, se almacenan en una lista asociada a dicha posición
La zona de memoria dinámica donde se almacenan las listas asociadas a cada posición de
la tabla se denomina: zona de desbordamiento

Pares <c,v> zona de desbordamiento


T
0
(c1, v1) h
1
Función de
(c2, v2) Dispersión .
(c3, v3)
.
max-1

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 30

Resolución de Colisiones
Dispersión cerrada: recolocación en la tabla

Consiste en almacenar los pares (clave, valor) cuya entrada primaria (índice) ya esté
ocupada (colisión), en otra posición libre de la propia tabla
Las colisiones se resuelven calculando una secuencia de huecos de dispersión se evita
el uso de estructuras auxiliares
Expresión para determinar la secuencia de búsqueda:
pk(c) = (h(c) + f(k)) mod max
c: clave a insertar
pk(c): posición a examinar en el k-ésimo intento (p0 es la posición inicial para c)
h(c): función de dispersión
f(k) : función que define la estrategia de búsqueda
Los pares (c,v) recolocados ocupan posiciones de futuras claves. El funcionamiento de
este método será bueno si el factor de carga α se mantiene por debajo de 0,8
Factor de carga α= n / max
n: nº de pares (c, v) almacenados en la tabla
max: tamaño de la tabla

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 31

Resolución de Colisiones
El factor de carga indica el nivel de ocupación de la tabla con pares almacenados
Si α = 1 n=max : Hay igual número de pares que de posiciones
Si α < 1 Hay menos pares que posiciones
Si α > 1 Hay más pares que posiciones

Prueba lineal
0
Probar sucesivamente en las posiciones que siguen a h(c) ⇒ f(k) = k :

pk(c) = (h(c) + k) mod max

h(c5) h(c3)
valor3 p1
c78 Prueba lineal
valor78
c5 pk h(c78) p2
valor5

c3

claves índices max-1

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 32

Resolución de Colisiones
Prueba cuadrática
f(k) = k2 :

pk(c) = (h(c) + k2) mod max 0

h(c5) h(c3)
valor3 p1
c78 Prueba cuadrática
valor78
c5 pk h(c78)

p2
c3 valor5

claves índices max-1

En la práctica, los conjuntos de clave tienden a tener distribuciones no exactamente uniformes,


agrupándose según determinados patrones, por lo que la prueba cuadrática suele producir
mejores resultados que la lineal

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 33

Resolución de Colisiones

Características de la dispersión cerrada

Los tiempos de las operaciones con la tabla tienden a degenerar cuando se trabaja
con un factor de carga alto ⇒ mejor mantenerlo por debajo de 0,8

En la secuencia de búsqueda se entremezclan claves procedentes de diferentes


valores de la función de dispersión

Se requiere algún mecanismo que permita distinguir una posición libre de la que no
lo está ⇒ asociar un valor lógico a cada posición de la tabla que indique si está o no
ocupada

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ 34

Resolución de Colisiones
Características de la dispersión cerrada

Búsqueda
1. Acceder a la posición h(c)
2. Si la posición está ocupada por c, fin de la búsqueda
3. Si la posición no está ocupada por c, seguir la misma secuencia de pk que se
empleó al insertar la clave, hasta encontrar la clave, una posición vacía o
finalizar la secuencia de índices pk

Este algoritmo de búsqueda plantea problemas si se permiten eliminaciones de


clave ⇒ el algoritmo podría finalizar con “no encontrado” al llegar a una posición
liberada por otra clave almacenada en una de las posiciones de la secuencia pk

Solución: marcar las posiciones de la tabla con uno de los valores {“libre”,
“ocupado”, “liberado”}. La búsqueda continuará al encontrar un valor “liberado”

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


4.6 Implementación de
+
diccionarios usando una
Tabla Dispersa

35
+ Implementación usando Tabla Dispersa 36

En este apartado presentamos una implementación utilizando una tabla dispersa y el


método de encadenamiento para resolver las colisiones (dispersión abierta)

Características del método de resolución de colisiones por encadenamiento:


Si el factor de carga α es pequeño, por probabilidad, la resolución de colisión
por encadenamiento es rápida → las listas de desbordamiento son cortas

Si la tabla tiene dimensión max y hay N pares (clave, valor), con una función
h uniforme, la longitud media de las listas es N / max

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ Implementación usando Tabla Dispersa 37

template <typename C, typename V, int h(C, int) >


class Diccionario {
public:
Diccionario();
Diccionario(int m);
void asignar(const Par<C,V>& p);
bool observar(const C& c, V& v);
void eliminar(const C& c);
~Diccionario();
private:
int max;
Lista< Par<C, V> >* t;
};

template <typename C, typename V, int h(C , int) >


Diccionario(int m)
Inicio
max = m
t = nuevo Lista< Par<C,V> >[m]
fin

Posición h(clave, máximo)

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ Implementación usando Tabla Dispersa 38

template <typename C, typename V , int h(C , int) >


void asignar(const Par<C,V>& p)
var
int entrada
Lista< Par<C,V> >::Iterador it
C clave
fvar
Inicio
clave = p.getClave()
entrada = h( clave, max )
si t[entrada].esVacia() entonces
t[entrada].anadirIzq( p )
sino
it = t[entrada].principio()
mientras it ≠ t[entrada].final() ∧
clave ≠ t[entrada].observar( it ).getClave() hacer
it.avanzar( t[entrada] )
fmientras
si it ≠ t[entrada].final() entonces
t[entrada].modificar( it, p ) modifica
sino
t[entrada].anadirIzq( p ) inserta
fsi
fsi
fin

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ Implementación usando Tabla Dispersa 39

template <typename C, typename V , int h(C , int) >


bool observar(const C& c, V& v)
var
int entrada
Lista< Par<C,V> >::Iterador it
fvar
inicio
entrada = h ( c, max )
si t[entrada].esVacia() entonces
devolver falso
sino
it = t[entrada].principio()
mientras it ≠ t[entrada].final() ∧
c ≠ t[entrada].observar( it ).getClave() hacer
it.avanzar( t[entrada] )
fmientras
si it ≠ t[entrada].final() entonces
v = t[entrada].observar( it ).getValor()
devolver verdad
sino
devolver falso
fsi
fsi
fin

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ Implementación usando Tabla Dispersa 40

template <typename C, typename V , int h(C , int) >


void eliminar(const C& c)
var
int entrada
Lista< Par<C,V> >::Iterador it
fvar
inicio
entrada = h ( c, max )
si ¬ t[entrada].esVacia() entonces
it = t[entrada].principio()
mientras it ≠ t[entrada].final() ∧
c ≠ t[entrada].observar( it ).getClave() hacer
it.avanzar( t[entrada] )
fmientras
si it ≠ t[entrada].final() entonces
t[entrada].eliminar( it )
fsi
fsi
fin

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática


+ Implementación usando Tabla Dispersa 41

Eficiencia de las operaciones

Operación Tabla Dispersa


encadenamiento

Diccionario

asignar

observar

eliminar

~Diccionario

n : número elementos del diccionario


m : tamaño de la tabla dispersa

Estructuras de Datos II Tema 4 Grado en Ingeniería Informática

También podría gustarte