Menu
Coddy logo textTech

Tabla Hash

Última actualización

Una tabla hash almacena elementos en un arreglo de cubetas. Para colocar o encontrar una clave, la pasa por una función hash y toma el resultado módulo el número de cubetas: eso da el índice de la cubeta en O(1). Pulsa reproducir arriba para ver cómo cada clave se convierte en hash hacia una cubeta y se almacena, y luego una búsqueda que salta directamente a la cubeta correcta.

Cuando dos claves caen en la misma cubeta -una colisión- esta visualización usa encadenamiento separado: cada cubeta contiene una pequeña lista y las claves que colisionan se añaden a ella. Mientras la tabla no esté demasiado llena (un factor de carga bajo) y el hash distribuya bien las claves, las cadenas permanecen cortas y la inserción, la búsqueda y el borrado son O(1) en promedio.

Complejidad temporal

OperaciónPromedioPeor caso
InsertarO(1)O(n) (todas las claves colisionan)
BúsquedaO(1)O(n)
BorrarO(1)O(n)
EspacioO(n)O(n)

Conceptos clave

TérminoSignificado
Función hashAsigna una clave a un índice de cubeta
ColisiónDos claves caen en la misma cubeta
Encadenamiento separadoCada cubeta contiene una lista de entradas que colisionan
Direccionamiento abiertoAlternativa: sondear la siguiente ranura libre
Factor de cargaentradas / cubetas: determina el redimensionamiento

Ejemplo resuelto

Insertando las claves 20, 34, 9, 13 en una tabla con 7 cubetas, usando hash(k) = k % 7:

PasoEstructuraAcción
Insertar 20cubeta 6: [20]20 % 7 = 6, cubeta 6 vacía, almacenar 20
Insertar 34cubeta 6: [20, 34]34 % 7 = 6, colisión con 20, añadir 34 a la cadena
Insertar 9cubeta 2: [9]9 % 7 = 2, cubeta 2 vacía, almacenar 9
Insertar 13cubeta 6: [20, 34, 13]13 % 7 = 6, colisión, añadir 13 a la cadena de la cubeta 6
Buscar 34cubeta 6: [20, 34, 13]34 % 7 = 6, recorrer cadena: 20 no, 34 coincide - encontrado

Cuándo usar una tabla hash

Úsala cuandoEvítala cuando
Necesitas inserción, búsqueda y borrado por clave en O(1) promedioNecesitas mantener las claves ordenadas - usa un BST balanceado
Las claves no tienen un orden útil y solo compruebas pertenencia por coincidencia exactaNecesitas consultas por rango o búsquedas de la clave más cercana
Puedes permitirte algo de memoria extra para cubetas y un factor de carga bajoLa memoria es extremadamente limitada y cada byte cuenta
Existe una buena función hash para tu tipo de claveLa latencia del peor caso debe estar acotada - las colisiones la hacen O(n)

Código de Hash Table

Una implementación limpia y ejecutable de Hash Table en Python, JavaScript, Java, C++, C. Elige un lenguaje, copia el código o ábrelo ya cargado en el Playground de Coddy.

Código de Hash Table en Python

Python
1class HashTable:2    def __init__(self, size=8):3        self.size = size4        self.buckets = [[] for _ in range(size)]5
6    def _index(self, key):7        # Hash the key to a bucket; different keys can collide8        return sum(ord(ch) for ch in key) % self.size9
10    def set(self, key, value):11        bucket = self.buckets[self._index(key)]12        for i, (k, _) in enumerate(bucket):13            if k == key:14                bucket[i] = (key, value)  # update existing key15                return16        bucket.append((key, value))  # chain on collision17
18    def get(self, key):19        for k, v in self.buckets[self._index(key)]:20            if k == key:21                return v22        raise KeyError(key)23
24    def delete(self, key):25        bucket = self.buckets[self._index(key)]26        for i, (k, _) in enumerate(bucket):27            if k == key:28                del bucket[i]29                return30        raise KeyError(key)31
32
33table = HashTable()34table.set("apple", 3)35table.set("banana", 7)36table.set("cherry", 5)37
38print("apple  ->", table.get("apple"))39print("banana ->", table.get("banana"))40table.set("apple", 10)41print("apple  ->", table.get("apple"))42table.delete("banana")43print("bucket sizes:", [len(b) for b in table.buckets])
Ejecuta este código en el Playground de Python

Preguntas frecuentes sobre la tabla hash

¿Qué es una colisión de hash y cómo se resuelve?
Una colisión ocurre cuando dos claves diferentes caen en la misma cubeta. Las dos soluciones comunes son el encadenamiento separado (cada cubeta contiene una lista y las claves que colisionan se añaden - mostrado aquí) y el direccionamiento abierto (sondear la siguiente ranura vacía del arreglo). Ambos mantienen correctas las búsquedas; se diferencian en la disposición de memoria y el rendimiento con carga alta.
¿Cuál es la complejidad temporal de una tabla hash?
La inserción, la búsqueda y el borrado son O(1) en promedio cuando la función hash distribuye las claves de forma uniforme y el factor de carga se mantiene bajo. En el peor caso -todas las claves colisionando en una sola cubeta- se degradan a O(n), por lo que importan una buena función hash y el redimensionamiento.
¿Qué es un factor de carga?
El factor de carga es el número de entradas almacenadas dividido por el número de cubetas. A medida que crece, las cadenas se alargan y las operaciones se ralentizan, por lo que la mayoría de las tablas hash se redimensionan (rehash a un arreglo mayor) cuando supera un umbral como 0.75.
¿Cuándo debo usar una tabla hash en lugar de un árbol binario de búsqueda?
Usa una tabla hash cuando solo necesitas búsquedas por coincidencia exacta y quieres velocidad O(1) promedio sin requisito de orden. Usa un árbol binario de búsqueda balanceado cuando necesitas claves ordenadas, consultas por rango o búsquedas de predecesor/sucesor, algo que una tabla hash no puede hacer eficientemente. Un BST ofrece operaciones O(log n) garantizadas, mientras que una tabla hash cambia esa garantía por un rendimiento promedio más rápido.
¿Cuál es la diferencia entre encadenamiento separado y direccionamiento abierto?
El encadenamiento separado almacena las claves que colisionan en una lista por cubeta, de modo que una cubeta puede contener muchas entradas y la tabla nunca se llena realmente. El direccionamiento abierto mantiene todo en el propio arreglo y sondea la siguiente ranura libre ante una colisión, lo cual es amigable con la caché pero se degrada bruscamente cuando el factor de carga se acerca a 1 y necesita un manejo cuidadoso del borrado. El encadenamiento tolera factores de carga más altos; el direccionamiento abierto usa la memoria de forma más compacta.
¿Por qué no puedo confiar en que una tabla hash mantenga mis claves en orden de inserción o de clasificación?
Una función hash dispersa deliberadamente las claves entre las cubetas para evitar aglomeraciones, por lo que el orden de iteración refleja la disposición de las cubetas, no el orden de inserción o de clasificación. Si necesitas orden, usa un mapa/árbol ordenado o una estructura como un mapa con orden de inserción (por ejemplo, el dict de Python preserva el orden de inserción, pero eso es una garantía del lenguaje, no una propiedad inherente de la tabla hash). Nunca asumas que el orden de iteración coincide con cómo insertaste las claves a menos que el lenguaje lo prometa explícitamente.
Coddy programming languages illustration

Domina los algoritmos con Coddy

COMENZAR