Tablas hash
Con 47 guardado en una tabla de 7 cubetas, la computadora va directo a la cubeta 47 mod 7 = 5 en lugar de buscar en toda la tabla.
Convertir una clave en una posición
Hasta ahora, encontrar un valor significaba buscar: hasta n pasos en un arreglo sin ordenar o en una lista enlazada. Pero los arreglos pueden llegar a cualquier posición en un paso. ¿Y si la propia clave te dijera la posición? Si tus claves fueran números enteros pequeños, digamos números de estudiante del 0 al 99, podrías tener un arreglo de 100 celdas y guardar al estudiante k en la celda k. Las notas del MIT lo llaman arreglo de acceso directo. Falla cuando las claves posibles son enormes, como números de teléfono o palabras, porque no puedes permitirte una celda para cada clave posible.
Una función hash lo resuelve comprimiendo cualquier clave en un rango pequeño de posiciones, de 0 a m − 1. Una sencilla para números enteros es h(k) = k mod m, el residuo de dividir entre m. El arreglo de m celdas es la tabla hash, y a sus celdas se les suele llamar cubetas (buckets). Para guardar 47 con m = 7, calcula 47 mod 7 = 5 y ponlo en la cubeta 5. Para encontrar 47 después, calcula lo mismo y mira solo en la cubeta 5.
Colisiones y encadenamiento
Hay un problema. Con 7 cubetas y más de 7 claves posibles, algunas claves tienen que compartir cubeta: 12, 33 y 47 dan todas residuo 5. Esto se llama colisión, y las notas del MIT señalan que no se puede evitar, por el principio del palomar. El remedio habitual es el encadenamiento: cada cubeta contiene una pequeña lista, una cadena, con todas las claves que fueron a parar ahí. Encontrar 47 cuesta entonces 1 paso por el hash más una comparación por cada clave revisada en la cadena 5. Si 12 y 33 están delante, son 1 + 3 = 4 pasos.
¿Qué largo tienen las cadenas? Si las claves se reparten de manera uniforme, cada cadena tiene unas n/m claves, un número llamado factor de carga. Mantén m más o menos tan grande como n y las cadenas siguen cortas, así que buscar, insertar y eliminar llevan en promedio un número constante de pasos. El peligro es un mal reparto. Si todas las claves van a la misma cubeta, una sola cadena contiene las n claves y la tabla no es mejor que una lista enlazada. En el laboratorio, pon 7 cubetas e inserta 14, 21 y 28: todas caen en la cubeta 0.
Arrastra para girar. Desplaza o pellizca para acercar.
Tablas hash en JavaScript
Rara vez escribirás tú mismo una tabla hash, porque JavaScript tiene Map y Set. La especificación de ECMAScript dice que "deben implementarse usando tablas hash u otros mecanismos que, en promedio, ofrezcan tiempos de acceso sublineales respecto al número de elementos". Dicho de otro modo, map.get(key) y set.has(x) deben ser más rápidos que buscar en toda la colección. MDN agrega que un Map conserva las claves en el orden de inserción y, a diferencia de un objeto normal, no contiene claves predeterminadas que puedan chocar con las tuyas.
const price = new Map();
price.set("apple", 1.2);
price.set("bread", 2.5);
console.log(price.get("bread")); // 2.5, sin recorrer la lista
console.log(price.has("milk")); // false
const seen = new Set([4, 8, 15]);
console.log(seen.has(8)); // true| Función hash | Convierte una clave en un número de cubeta de 0 a m − 1, por ejemplo k mod m. |
| Colisión | Dos claves distintas reciben la misma cubeta. Es inevitable cuando hay más claves que cubetas. |
| Encadenamiento | Cada cubeta guarda una lista de todas las claves que fueron a parar ahí. |
| Factor de carga | n/m, el largo promedio de las cadenas. |
| Map y Set | Las colecciones con clave integradas en JavaScript, que deben ser más rápidas que lineales en promedio. |
- Con h(k) = k mod 7, ¿en qué cubeta va 47?
- La tabla contiene 12, 25, 33, 47, 70 (insertados en ese orden) con m = 7. ¿Cuántos pasos lleva encontrar 47 (1 por el hash más las claves comparadas)?
- La misma tabla: ¿cuántos pasos para encontrar 12?
- La misma tabla: 19 no está guardado. ¿Cuántos pasos lleva buscar 19?
- La misma tabla: ¿cuál es el factor de carga n/m? (con dos decimales)
- ¿Qué es una colisión?
- Una clave demasiado grande
- Dos claves distintas que el hash manda a la misma cubeta
- Eliminar una clave dos veces
- Una tabla sin claves
- ¿Por qué ninguna función hash puede evitar las colisiones cuando hay más claves posibles que cubetas?
- Las computadoras redondean los números
- Por el principio del palomar
- Las claves siempre son pares
- Las cadenas son demasiado cortas
- Si todas las claves caen en la misma cubeta, ¿cómo se comporta la búsqueda de una clave?
- Sigue siendo 1 paso
- Como buscar en una lista enlazada de n claves
- Se vuelve imposible
- Como la búsqueda binaria
- ¿Qué exige la especificación de ECMAScript a los tiempos de acceso de Map?
- Exactamente 1 paso
- Sublineales respecto al número de elementos, en promedio
- Θ(n log n)
- Nada
- El hash de Luhn de 1953 sumaba pares de dígitos vecinos y se quedaba con el último dígito de cada suma. ¿En qué se convierte 31415926?
- Una función hash convierte una clave en un número de cubeta; k mod m es una sencilla.
- Las colisiones son inevitables; el encadenamiento guarda una lista en cada cubeta.
- Con un factor de carga n/m pequeño, buscar, insertar y eliminar llevan en promedio un número constante de pasos.
- Map y Set de JavaScript deben ser más rápidos que lineales en promedio.
Fuentes de este curso (11)
- MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
- lecture notes 2 Data Structures (interface vs data structure, Sequence and Set interfaces, stack = insert_last/delete_last, queue = insert_last/delete_first, array, linked list, dynamic array, amortized Θ(1) append)
- 4 Hashing (chaining, pigeonhole collisions, chain length n/m)
- 6 Binary Trees Part 1 (height, traversal order, O(h) operations) and 7 Binary Trees Part 2: AVL (Adelson-Velsky and Landis, 1962) at ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes
- MDN Web Docs, Array.prototype.shift (shifts all values left by 1)
- Array.prototype.unshift, Map (insertion order, Map vs Object, spec requires sublinear average access) and Set (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects)
- ECMAScript 2025 Language Specification (tc39.es/ecma262)
- 24.1 Map Objects and 24.2 Set Objects ("must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements")
- Array.prototype.shift steps (Repeat, while k < len: move element k to k - 1)
- D. E. Knuth, The Art of Computer Programming vol. 3 (2nd ed. 1998) section 6.4 History (H. P. Luhn, IBM internal memorandum January 1953, hashing with chaining; digit pairs added mod 10, 31415926 -> 4548) via gwern.net copy, and IEEE Spectrum, "Hans Peter Luhn and the Birth of the Hashing Algorithm" (2018)
- "A brief history of the stack", SIGCIS (sigcis.org/files/A brief history.pdf: Bauer and Samelson applied for the patent in 1957, US 3,047,228 granted July 31, 1962; IPL list processing by Newell, Simon and Shaw at RAND 1956) and Wikipedia, Information Processing Language (Newell, Shaw, Simon, RAND and Carnegie Institute of Technology, about 1956).
Fecha de consulta: 2026-10-18