Una hash table transforma una clave en una posición aproximada mediante una hash function. Su objetivo es localizar datos sin recorrer toda la colección.
Texto
key ─hash→ integer ─indexing→ bucket
Varias claves pueden producir el mismo bucket. Eso se llama collision y no es un error excepcional: toda implementación debe resolverlo.
Una hash function determinista debe producir el mismo hash para la misma clave durante la vida de la tabla.
Una buena función para una tabla busca:
distribuir claves de manera uniforme;
usar toda la información relevante;
ser rápida;
producir cambios amplios ante cambios pequeños en la clave;
evitar patrones previsibles del dominio.
No debe confundirse con hashing criptográfico. Una tabla necesita distribución y velocidad; contraseñas necesitan resistencia a ataques y funciones deliberadamente costosas.
Esta implementación enseña estructura, no producción. find, splice, flat y el rehash recursivo mediante set tienen costos y decisiones que una biblioteca madura optimiza.
Prueba desplazamientos cuadráticos. Reduce clustering primario, pero necesita una política compatible con la capacidad para garantizar que encuentre posiciones.
No puedes convertir una posición eliminada directamente en “vacía”. Una búsqueda que depende de la cadena de probes podría terminar antes de llegar a una clave posterior.
Usa un marcador tombstone:
Texto
EMPTY → nunca se ocupó; búsqueda puede terminar
DELETED → se ocupó; búsqueda debe continuar
OCCUPIED → contiene entrada
Demasiados tombstones degradan rendimiento y pueden justificar rehashing.
En chaining puede superar 1. En open addressing debe ser menor que 1 y el rendimiento empeora al acercarse a la capacidad.
El umbral exacto es una decisión de implementación. Un valor como 0.75 equilibra memoria y longitud esperada de búsquedas, pero no es una ley universal.
Si dos claves se consideran iguales, deben producir el mismo hash.
Lo contrario no es necesario: claves distintas pueden colisionar.
Si la igualdad depende de id, el hash también debe derivarse de id. Mutar campos usados por hash mientras una clave está almacenada puede volverla inencontrable en lenguajes con custom keys.
Un atacante puede enviar claves diseñadas para colisionar y degradar operaciones a O(n). Runtimes y frameworks pueden usar semillas aleatorias, funciones resistentes o estructuras alternativas en buckets.
Esto importa en endpoints públicos, headers, parámetros y parsers, no solo en entrevistas.
Que Map de JavaScript preserve orden de inserción no significa que una hash table genérica esté ordenada por clave. El orden observable es una garantía específica de la API, no una propiedad natural del hashing.
Si las claves son enteros densos y pequeños, un array puede ser mejor:
TypeScript
const counts =Array(maxValue +1).fill(0);
Lookup verdadero por índice O(1), menor overhead y buena localidad. La hash table aporta flexibilidad para dominios dispersos o tipos de clave más generales.
¿Por qué duplicar la capacidad obliga a recalcular la posición de todas las entradas?
Respuesta
Porque el índice suele depender de hash mod capacity. Al cambiar la capacidad, el mismo hash puede corresponder a otro bucket. Copiar la entrada en el índice antiguo rompería futuras búsquedas.