Datos del enunciado: tabla de tamaño M = 7, función hash h(k) = k mod 7, claves a insertar en orden: 19, 26, 12, 5, 33.
Cuestión 1 — Posición teórica de cada clave (h(k) = k mod 7)
Calculamos el valor hash de cada clave antes de resolver colisiones:
\begin{aligned}
h(19) &= 19 \bmod 7 = 5 \quad (19 = 2\cdot 7 + 5) \\
h(26) &= 26 \bmod 7 = 5 \quad (26 = 3\cdot 7 + 5) \;\;\leftarrow\; \text{colisiona con } 19 \\
h(12) &= 12 \bmod 7 = 5 \quad (12 = 1\cdot 7 + 5) \;\;\leftarrow\; \text{colisiona con } 19 \text{ y } 26 \\
h(5) &= \phantom{0}5 \bmod 7 = 5 \quad (\phantom{0}5 = 0\cdot 7 + 5) \;\;\leftarrow\; \text{colisiona con } 19,\, 26 \text{ y } 12 \\
h(33) &= 33 \bmod 7 = 5 \quad (33 = 4\cdot 7 + 5) \;\;\leftarrow\; \text{colisiona con todas}
\end{aligned}
| Clave |
k mod 7 |
Cubeta destino |
| 19 |
5 |
5 |
| 26 |
5 |
5 |
| 12 |
5 |
5 |
| 5 |
5 |
5 |
| 33 |
5 |
5 |
Resultado clave: todas las claves del conjunto son congruentes con 5 módulo 7, es decir, todas son de la forma 7q + 5. Por tanto las cinco claves colisionan en la misma cubeta (índice 5). Es el caso peor posible para una función hash: un reparto totalmente degenerado en el que la función no dispersa nada. Esto se debe a que el conjunto elegido pertenece a una única clase de equivalencia módulo 7 (todas dejan resto 5). Una función hash de calidad debería repartir uniformemente; aquí el supuesto lo provoca a propósito para forzar la gestión de colisiones.
Cuestión 2 — Resolución por sondeo lineal (open addressing)
En sondeo lineal, ante colisión se prueba la secuencia de posiciones (h(k) + i) mod 7, con i = 0, 1, 2, ..., hasta encontrar un hueco libre. Insertamos respetando el orden dado.
Paso a paso:
Insertar 19: h=5. Posición 5 libre → 19 va a [5]
Insertar 26: h=5. [5] ocupada (19) → i=1: (5+1) mod 7 = 6 libre → 26 va a [6]
Insertar 12: h=5. [5] ocupada (19) → i=1: 6 ocupada (26)
→ i=2: (5+2) mod 7 = 0 libre → 12 va a [0]
Insertar 5: h=5. [5] ocupada → i=1: 6 ocupada
→ i=2: 0 ocupada (12)
→ i=3: (5+3) mod 7 = 1 libre → 5 va a [1]
Insertar 33: h=5. [5] ocupada → i=1: 6 ocupada
→ i=2: 0 ocupada
→ i=3: 1 ocupada (5)
→ i=4: (5+4) mod 7 = 2 libre → 33 va a [2]
Contenido final de la tabla (sondeo lineal):
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 620 120" font-family="ui-sans-serif, system-ui, Arial, sans-serif">
<text x="20" y="46" font-size="13" font-weight="bold" fill="#0f172a">Índice</text>
<text x="20" y="86" font-size="13" font-weight="bold" fill="#0f172a">Valor</text>
<!-- celdas -->
<rect x="100" y="30" width="68" height="60" rx="4" fill="#eff6ff" stroke="#334155" stroke-width="1.5"/>
<rect x="168" y="30" width="68" height="60" rx="4" fill="#eff6ff" stroke="#334155" stroke-width="1.5"/>
<rect x="236" y="30" width="68" height="60" rx="4" fill="#eff6ff" stroke="#334155" stroke-width="1.5"/>
<rect x="304" y="30" width="68" height="60" rx="4" fill="#f8fafc" stroke="#334155" stroke-width="1.5"/>
<rect x="372" y="30" width="68" height="60" rx="4" fill="#f8fafc" stroke="#334155" stroke-width="1.5"/>
<rect x="440" y="30" width="68" height="60" rx="4" fill="#ecfdf5" stroke="#334155" stroke-width="1.5"/>
<rect x="508" y="30" width="68" height="60" rx="4" fill="#eff6ff" stroke="#334155" stroke-width="1.5"/>
<!-- índices -->
<text x="134" y="46" font-size="12" fill="#334155" text-anchor="middle">0</text>
<text x="202" y="46" font-size="12" fill="#334155" text-anchor="middle">1</text>
<text x="270" y="46" font-size="12" fill="#334155" text-anchor="middle">2</text>
<text x="338" y="46" font-size="12" fill="#334155" text-anchor="middle">3</text>
<text x="406" y="46" font-size="12" fill="#334155" text-anchor="middle">4</text>
<text x="474" y="46" font-size="12" fill="#334155" text-anchor="middle">5</text>
<text x="542" y="46" font-size="12" fill="#334155" text-anchor="middle">6</text>
<!-- valores -->
<text x="134" y="78" font-size="16" font-weight="bold" fill="#0f172a" text-anchor="middle">12</text>
<text x="202" y="78" font-size="16" font-weight="bold" fill="#0f172a" text-anchor="middle">5</text>
<text x="270" y="78" font-size="16" font-weight="bold" fill="#0f172a" text-anchor="middle">33</text>
<text x="338" y="78" font-size="16" fill="#94a3b8" text-anchor="middle">—</text>
<text x="406" y="78" font-size="16" fill="#94a3b8" text-anchor="middle">—</text>
<text x="474" y="78" font-size="16" font-weight="bold" fill="#059669" text-anchor="middle">19</text>
<text x="542" y="78" font-size="16" font-weight="bold" fill="#0f172a" text-anchor="middle">26</text>
</svg>
Justificación: se observa el fenómeno de clustering primario (agrupamiento primario): como todas las claves caen en el mismo punto de arranque (5) y el sondeo es lineal, se forma un único bloque contiguo de posiciones ocupadas que se va alargando. Cada nueva inserción debe recorrer todo el racimo antes de encontrar hueco, por lo que el número de sondeos crece linealmente con cada inserción (1, 2, 3, 4, 5 sondeos respectivamente). Este es precisamente el inconveniente teórico del sondeo lineal frente a otras estrategias de direccionamiento abierto (sondeo cuadrático o doble hashing), que rompen ese agrupamiento.
Cuestión 3 — Resolución por encadenamiento separado (chaining)
En encadenamiento separado, cada cubeta [i] es la cabeza de una lista enlazada; toda clave con h(k) = i se añade a esa lista, sin desplazarse a otras cubetas. Adoptamos el criterio de insertar al final de la lista (preserva el orden de inserción del enunciado y facilita la lectura; insertar al inicio sería igualmente válido si se justifica, pero invertiría el orden).
Resultado:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 320" font-family="ui-sans-serif, system-ui, Arial, sans-serif">
<!-- columna de cubetas -->
<rect x="20" y="20" width="60" height="34" rx="4" fill="#eff6ff" stroke="#334155" stroke-width="1.5"/>
<rect x="20" y="60" width="60" height="34" rx="4" fill="#eff6ff" stroke="#334155" stroke-width="1.5"/>
<rect x="20" y="100" width="60" height="34" rx="4" fill="#eff6ff" stroke="#334155" stroke-width="1.5"/>
<rect x="20" y="140" width="60" height="34" rx="4" fill="#eff6ff" stroke="#334155" stroke-width="1.5"/>
<rect x="20" y="180" width="60" height="34" rx="4" fill="#eff6ff" stroke="#334155" stroke-width="1.5"/>
<rect x="20" y="220" width="60" height="34" rx="4" fill="#ecfdf5" stroke="#2563eb" stroke-width="2"/>
<rect x="20" y="260" width="60" height="34" rx="4" fill="#eff6ff" stroke="#334155" stroke-width="1.5"/>
<text x="50" y="42" font-size="13" font-weight="bold" fill="#0f172a" text-anchor="middle">[0]</text>
<text x="50" y="82" font-size="13" font-weight="bold" fill="#0f172a" text-anchor="middle">[1]</text>
<text x="50" y="122" font-size="13" font-weight="bold" fill="#0f172a" text-anchor="middle">[2]</text>
<text x="50" y="162" font-size="13" font-weight="bold" fill="#0f172a" text-anchor="middle">[3]</text>
<text x="50" y="202" font-size="13" font-weight="bold" fill="#0f172a" text-anchor="middle">[4]</text>
<text x="50" y="242" font-size="13" font-weight="bold" fill="#0f172a" text-anchor="middle">[5]</text>
<text x="50" y="282" font-size="13" font-weight="bold" fill="#0f172a" text-anchor="middle">[6]</text>
<!-- cubetas vacías → ∅ -->
<text x="100" y="42" font-size="14" fill="#94a3b8">→ ∅</text>
<text x="100" y="82" font-size="14" fill="#94a3b8">→ ∅</text>
<text x="100" y="122" font-size="14" fill="#94a3b8">→ ∅</text>
<text x="100" y="162" font-size="14" fill="#94a3b8">→ ∅</text>
<text x="100" y="202" font-size="14" fill="#94a3b8">→ ∅</text>
<text x="100" y="282" font-size="14" fill="#94a3b8">→ ∅</text>
<!-- lista enlazada de la cubeta 5 -->
<!-- flecha cabeza -> primer nodo -->
<line x1="80" y1="237" x2="118" y2="237" stroke="#2563eb" stroke-width="1.8"/>
<polygon points="118,233 126,237 118,241" fill="#2563eb"/>
<!-- nodo 19 -->
<rect x="126" y="220" width="52" height="34" rx="4" fill="#ecfdf5" stroke="#059669" stroke-width="1.5"/>
<text x="152" y="242" font-size="14" font-weight="bold" fill="#0f172a" text-anchor="middle">19</text>
<line x1="178" y1="237" x2="216" y2="237" stroke="#334155" stroke-width="1.8"/>
<polygon points="216,233 224,237 216,241" fill="#334155"/>
<!-- nodo 26 -->
<rect x="224" y="220" width="52" height="34" rx="4" fill="#f8fafc" stroke="#334155" stroke-width="1.5"/>
<text x="250" y="242" font-size="14" font-weight="bold" fill="#0f172a" text-anchor="middle">26</text>
<line x1="276" y1="237" x2="314" y2="237" stroke="#334155" stroke-width="1.8"/>
<polygon points="314,233 322,237 314,241" fill="#334155"/>
<!-- nodo 12 -->
<rect x="322" y="220" width="52" height="34" rx="4" fill="#f8fafc" stroke="#334155" stroke-width="1.5"/>
<text x="348" y="242" font-size="14" font-weight="bold" fill="#0f172a" text-anchor="middle">12</text>
<line x1="374" y1="237" x2="412" y2="237" stroke="#334155" stroke-width="1.8"/>
<polygon points="412,233 420,237 412,241" fill="#334155"/>
<!-- nodo 5 -->
<rect x="420" y="220" width="52" height="34" rx="4" fill="#f8fafc" stroke="#334155" stroke-width="1.5"/>
<text x="446" y="242" font-size="14" font-weight="bold" fill="#0f172a" text-anchor="middle">5</text>
<line x1="472" y1="237" x2="510" y2="237" stroke="#334155" stroke-width="1.8"/>
<polygon points="510,233 518,237 510,241" fill="#334155"/>
<!-- nodo 33 -->
<rect x="518" y="220" width="52" height="34" rx="4" fill="#f8fafc" stroke="#334155" stroke-width="1.5"/>
<text x="544" y="242" font-size="14" font-weight="bold" fill="#0f172a" text-anchor="middle">33</text>
<line x1="570" y1="237" x2="608" y2="237" stroke="#334155" stroke-width="1.8"/>
<polygon points="608,233 616,237 608,241" fill="#334155"/>
<!-- ∅ final -->
<text x="622" y="242" font-size="16" fill="#94a3b8">∅</text>
</svg>
(Si se hubiera elegido inserción al inicio de la lista, la cubeta 5 quedaría 33 → 5 → 12 → 26 → 19.)
Justificación: todas las claves comparten cubeta, por lo que la tabla degenera en una única lista enlazada de 5 nodos colgando del índice 5, mientras las otras seis cubetas quedan vacías. La estructura se comporta entonces como una lista lineal: la búsqueda de la última clave insertada exige recorrer los 5 elementos, de modo que el coste de búsqueda en el peor caso es O(n). A diferencia del sondeo lineal, el encadenamiento no sufre clustering primario ni puede "llenarse" (admite más de M claves), pero a cambio consume memoria extra en punteros y pierde localidad de caché.
Cuestión 4 — Factor de carga y su influencia en el rendimiento
El factor de carga se define como:
\lambda = \frac{n}{M}
donde n es el número de claves almacenadas y M el número de cubetas. En este supuesto:
\lambda = \frac{5}{7} \approx 0{,}714 \quad (\approx 71{,}4\,\%)
Influencia en el rendimiento (caso ideal de dispersión uniforme):
-
Direccionamiento abierto / sondeo lineal: el coste medio de una búsqueda con éxito se aproxima a \frac{1}{2}\left(1 + \frac{1}{1-\lambda}\right) y la sin éxito a \frac{1}{2}\left(1 + \frac{1}{(1-\lambda)^2}\right). Como \frac{1}{1-\lambda} crece de forma explosiva cuando \lambda \to 1, el rendimiento se degrada bruscamente al llenarse la tabla. Por eso en sondeo lineal se recomienda mantener \lambda \le 0{,}7\text{–}0{,}75 y aplicar rehashing (reconstruir la tabla con un M mayor, normalmente primo) al superar ese umbral. Además, λ nunca puede exceder 1 (no caben más de M claves).
-
Encadenamiento separado: el coste medio de búsqueda es del orden de 1 + \frac{\lambda}{2} (con éxito) o 1 + \lambda (sin éxito), es decir, crece linealmente y de forma suave con λ, ya que λ es simplemente la longitud media de las listas. Admite \lambda > 1 sin colapsar, aunque conviene también rehashear para que las listas no se alarguen en exceso.
Conclusión y comparativa:
| Aspecto |
Sondeo lineal |
Encadenamiento separado |
| Almacenamiento |
Dentro del propio array |
Listas enlazadas externas |
| λ máximo |
< 1 (se llena) |
sin límite (>1 posible) |
| Degradación con λ alto |
Brusca (clustering) |
Suave (listas más largas) |
| Memoria |
Solo el array |
Array + punteros |
| Localidad de caché |
Buena |
Peor (saltos de punteros) |
El caso de este supuesto es deliberadamente patológico: una función hash que envía todas las claves a la misma cubeta hace que ambas técnicas degeneren en una búsqueda lineal O(n), evidenciando que el rendimiento de una tabla hash depende tanto de una buena función de dispersión como de mantener controlado el factor de carga mediante rehashing. Lo idóneo es elegir M primo, una función hash que distribuya uniformemente y conservar λ por debajo de un umbral razonable.