PROYECTO FINAL. Tutorial para publicar en SlideShare.pptx
Tema 2 Diccionarios. Tablas Hash.
1. Análisis y Diseño
de Software
Tema 2c.
Diccionarios.
Tablas Hash
Carlos A. Iglesias <cif@gsi.dit.upm.es>
Departamento de Ingeniería de Sistemas Telemáticos
http://moodle.dit.upm.es
2. Leyenda
Teoría
Ejercicio práctico en el ordenador
Ampliación de conocimientos
Lectura / Vídeo / Podcast
Práctica libre / Experimentación
Explicación en pizarra
Diccionarios. Tablas Hash 2
3. Bibliografía
● Beginning Algorithms, Simon
Harris and James Ross, Wrox,
2005.
● Capítulo 11
http://proquest.safaribooksonline.com/book/software-e
ngineering-and-development/algorithms/9780764596742
Diccionarios. Tablas Hash 3
4. Temario
● Tablas Hash
● Direccionamiento abierto y cerrado
● Implementación de diccionario con Hash
● Complejidad en tablas hash
Diccionarios. Tablas Hash 4
5. Objetivos
● Comprender cómo funciona la estructura
de datos tabla hash
● Comprender qué es una función hash
● Saber evaluar la complejidad de una
tabla hash
● Aprender a implementar un diccionario
con una tabla hash
Diccionarios. Tablas Hash 5
6. Objetivo
● Hemos visto que
podíamos obtener
una complejidad
O(logn) de árboles
de búsqueda binaria
con diccionarios
● ¿Podemos reducir
aún más la
complejidad del
diccionario?
Diccionarios. Tablas Hash 6
7. Tabla Hash (I)
● Guardamos valores en una tabla (array)
● A cada valor le asignamos una posición
única que se calcula mediante una fórmula
matemática (función hash)
– No hace falta recorrer la tabla para
encontrarlo, insertarlo o borrarlo → basta
aplicar la fórmula → O(1)
Diccionarios. Tablas Hash 7
8. Tabla Hash (II)
● Pero...
– En el array habrá valores 'ocupados' y 'no
ocupados' alternados → no están los sitios
libres al final, hay que buscarlos
– No guardamos de forma ordenada
– Si hay claves duplicadas, se da una colisión
(dos valores con la misma clave) → ¿qué
hacemos?
Diccionarios. Tablas Hash 8
9. Función Hash
● Toma un objeto y devuelve un 'valor
hash', normalmente un entero
Objeto Valor Hash
h
Diccionarios. Tablas Hash 9
10. Ej. Función Hash para String
● Suma de los valores de las letras
(ej. a = 1, o bien ASCII)
– h('elvis') = 5 + 12 + 22 + 9 + 19 = 67
– h('madonna') = 13 +1+ 4 +15+14 + 14 + 1 = 62
– h('sting') = 19 + 20 + 9 + 14 + 7 = 69
● Cumple que asignamos una posición del
array a cada entrada
Diccionarios. Tablas Hash 10
11. Problemas función hash (I)
● No es eficiente almacenando → Dejamos
hasta el 67 todas las posiciones vacías
– → Podemos poner valores hash en un rango
con una función módulo, ej %10
• h('elvis') = 67 % 10 = 7
• h('madonna') = 62 % 10 = 2
• h('sting') = 69 % 10 = 9
● Hay muchas colisiones, palabras que dan
lo mismo. Ej. h('lives') = 67 % 10 = 7
Diccionarios. Tablas Hash 11
12. Problemas función hash (II)
● Intentamos que cuente la posición de la letra,
para que salgan cosas diferentes
● Multiplicamos por un número primo (31) las
letras antes de sumarlas
● h('elvis')
= (((e * 31 + l) * 31 + v) * 31 + i) * 31
+ s % 11 = 4996537 % 11 = 7
● h('madonna') = 3; h('sting') = 5; h('lives') = 8
→ Se comporta como queremos
Diccionarios. Tablas Hash 12
13. Problemas Función Hash (III)
● Pero... si añadimos 'fred', F(hfred') = 7, que colisiona con
'elvis'
● Podríamos ampliar el tamaño de la tabla (en vez de % 11,
p. ej. % 17) o incluso disminuir el tamaño, pero no parece
una solución buena, puede que haya colisiones
●→ Hay que ver cómo tratar estas colisiones.
● Dos métodos
– Direccionamiento abierto (o hashing cerrado): prueba lineal
– Direccionamiento cerrado (o hashing abierto): lista de valores
Diccionarios. Tablas Hash 13
14. Direccionamiento abierto (I)
● Busco sitio de
forma lineal
● h('fred') = 7 →
colisión con 'elvis'
● Busco siguiente
→ ocupado 'lives'
● Busco siguiente
→ meto 'fred' en 9
Diccionarios. Tablas Hash 14
15. Direccionamiento abierto (II)
● Sup. ya he metido
'mary', h('mary') = 10
● Meto 'tim', h('tim') = 9
→ colisión con 'fred'
● Siguiente → colisión
con 'mary'
● Siguiente (inicio) →
meto en posición 0
Diccionarios. Tablas Hash 15
16. Variantes
direccionamiento abierto
● Podemos definir varias formas de prueba,
siendo i el número de intento de inserción de
la clave
● Prueba lineal hi ( x)=(h( x)+i) mod M
● Prueba cuadrática hi ( x)=( h( x)+i 2 ) mod M
● Hashing doble hi ( x)=( h( x)+i∗h' ( x )) mod M
siendo h' una función hash secundaria, que
no tome el valor 0, p.ej. siendo q un número
primo menor que M
h' ( x )=q−( x mod q)
Diccionarios. Tablas Hash 16
17. Análisis
● Con la lineal conseguiremos ocupar los huecos de
forma consecutiva, y se forman ristras de valores y
si caemos en una, hay que recorrerla hasta el final
● Con la cuadrática, los valores están menos
aglomerados y hay huecos entre ellos, y es menos
probable caer en una 'ristra'
● Con la doble función hash, aún habrá más huecos,
y habrá menos ristras que recorrer
Diccionarios. Tablas Hash 17
18. Ej. Prueba lineal hashCode()
● Implementación hashCode() de String
● Debemos implementar hashCode() si
sobreescribimos equals() para colecciones
como java.util.HashMap
Diccionarios. Tablas Hash 18
19. Direccionamiento cerrado
● Tenemos en una
lista los que tienen
la misma clave
● Búsqueda lineal
en la lista.
● Podemos
aumentar el tamaño
de la tabla para
reducir colisiones
Diccionarios. Tablas Hash 19
20. Factor de carga y rehashing
● Factorde carga: número de valores almacenados /
tamaño de la tabla
● Ej. anterior 16 / 11 = 1.45 → 145%
● Un factor de carga razonable:
– 0.75, 75%, buen compromiso tiempo-espacio
– Debe ser < 1.0 siempre, lo normal < 0.8
● Cuando superamos el factor de carga hacemos
'rehashing' (calcular otra vez la función hash)
– Ampliamos el tamaño de la tabla
– Seleccionamos otro valor de M, que será el primo más grande
inferior al tamaño de la tabla
Diccionarios. Tablas Hash 20
21. Complejidad
● Direccionamiento abierto, sondeo
– Si hay pocas colisiones → O(1)
– Si hay más, tenemos que recorrer → O(n)
● Direccionamiento cerrado, listas de valores
– Insertar, buscar, borrar: O(1) + O(lista)
– Si la tabla tiene pocas colisiones, lista.size() = 1 → O(1)
● Esdecir, o gastamos más espacio, o gastamos
más tiempo. Si la tabla tiene tamaño h
– T(n) → O(n/h); si h → n, O(1)
– E(n) → O(h); si h → n, O(n)
Diccionarios. Tablas Hash 21
22. Complejidad T(n)
Algoritmo search put get remove
Búsqueda lineal O(n) O(1) O(n) O(n)
Búsqueda binaria iterativa O(logn) O(n) O(logn) O(n)
Búsqueda binaria O(logn) O(n) O(logn) O(n)
recursiva
Árbol binario de búsqueda O(logn) O(logn O(logn) O(logn)
)
Hash con listas O(1) k > N; O(N) k << N
Hash abierto con prueba O(1) si carga << 1
Diccionarios. Tablas Hash 22
28. Tabla Hash en Java
● En Java tenemos la interfaz java.utilMap<K,V>
– void clear()
– boolean containsKey(Object key)
– boolean containsValue(Object value)
– Collection<V> values()
– Set<K> keySet()
– V put(K key, V value)
– V get(Object key)
– V remove(Object key)
– boolean isEmpty()
– int size()
Diccionarios. Tablas Hash 30
29. Algunas implementaciones de
Map<K,V>
● HashMap
– Usa tabla hash con listas para colisiones
– Hace un rehashing duplicando el tamaño de la tabla cuando se llena
– No está sincronizada para cuando veamos concurrencia
– Ofrece O(1)
● TreeMap
– Es un árbol de búsqueda, mantiene los datos ordenados
– No está sincronizada para cuando veamos concurrencia
– Complejidad: garantiza log(n)
Diccionarios. Tablas Hash 31
30. Resumen
● Las tablas hash permiten obtener tiempos de
O(1), si están bien dimensionadas
● Las tablas hash actúan quitan el sentido el orden
en los datos
● Una función hash 'perfecta' sin colisiones es
difícil de conseguir
● El compromiso tiempo / espacio es ampliar la
tabla para reducir colisiones
● Las tablas hash con listas dan muy buenas
prestaciones O(1)
Diccionarios. Tablas Hash 32