59 15 68 3 21 67 82 8 16 51 81 98 401) Recorridos inorden, preorden y postorden. 2) Insertar 47, 73, 54. 3) Eliminar 67 y 82 del árbol inicial.
El recorrido por niveles se lee fila a fila de arriba abajo. Así queda el árbol:
Preorden: 18 → 9 → 8 → 16 → 13 → 21 → 19 → 77 → 26 → 61 → 67 → 89 → 90
Postorden: 8 → 13 → 16 → 9 → 19 → 21 → 67 → 61 → 26 → 90 → 89 → 77 → 18
30, 7, 8, 45, 98, 72, 91, 25, 73, 12Idea general
Heapsort tiene dos fases: primero construye un max-heap (árbol donde cada padre es mayor que sus hijos), y luego extrae el máximo repetidamente colocándolo al final del array.
Empezamos heapify desde el índice n/2−1 = 4 hacia la izquierda:
Valor 98, hijos: 73 y 12
98 es mayor que ambos hijos → sin intercambio.
Valor 45, hijos: 25 y 73
73 > 45 → intercambio(45, 73)
Valor 8, hijos: 72 y 91
91 > 8 → intercambio(8, 91). El 8 baja a pos 6, sin más hijos en rango.
Valor 7, hijos: 73 y 98
98 > 7 → intercambio(7, 98). El 7 baja a pos 4, hijos: 45 y 12. 45 > 7 → intercambio(7, 45). El 7 baja a pos 8, sin más hijos.
Valor 30, hijos: 98 y 91
98 > 30 → intercambio(30, 98). Baja a pos 1, hijos: 73 y 45. 73 > 30 → intercambio(30, 73). Baja a pos 3, hijos: 25 y 7. 30 > ambos → fin.
✓ Max-heap construido: 98, 73, 91, 30, 45, 72, 8, 25, 7, 12
swap(98, 12) → heapify [0..8]
swap(91, 7) → heapify [0..7]
swap(73, 25) → heapify [0..6]
swap(72, 8) → heapify [0..5]
swap(45, 7) → heapify [0..4]
swap(30, 7) → heapify [0..3]
swap(25, 7) → heapify [0..2]
swap(12, 8) → heapify [0..1]
swap(8, 7) → fin
| A | B | C | D | E | F | G | H | I | |
|---|---|---|---|---|---|---|---|---|---|
| A | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| B | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
| C | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| D | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
| E | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| F | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| G | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
| H | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| I | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
B: → G → H
C: → A
D: → E
E: → C
F: → A → C
G: → F → I
H: → C → D → E
I: → F
Regla: siempre elegir el vecino menor alfabéticamente
Pila inicial: [B]. Visito B → vecinos G, H → elijo G primero.
B → G (vecinos F, I → F primero) → F (vecinos A, C → A primero) → A (sin vecinos sin visitar, retrocedo) → C (sin vecinos sin visitar, retrocedo a F) → retrocedo a G → I → F (ya visitado, retrocedo) → retrocedo a B → H → C (visitado) → D → E → C (visitado, retrocedo) → fin.
Cola FIFO, vecinos en orden alfabético
Cola: [B]. Proceso B → encolo G, H. Cola: [G, H].
Proceso G → encolo F, I. Cola: [H, F, I].
Proceso H → encolo C, D, E (G ya visitado). Cola: [F, I, C, D, E].
Proceso F → A (C ya encolado). Cola: [I, C, D, E, A].
Proceso I → F ya visitado. Cola: [C, D, E, A].
Proceso C → A ya encolado. Proceso D, E, A → sin nuevos.
Algoritmo: eliminar nodos con grado entrada 0 repetidamente
Grados entrada: A=3, B=0, C=4, D=1, E=2, F=2, G=1, H=1, I=1.
Solo B tiene grado 0 → sacamos B, reducimos grados de G y H.
Ahora G=0, H=0 → sacamos G (menor), reducimos F e I → sacamos H, reducimos C, D, E.
I=0 → sacamos I, reduce F → F=0 → sacamos F, reduce A y C → D=0, E=0 → sacamos D → reduce E ya en 0 → sacamos E, reduce C → C=0 → sacamos C, reduce A → A=0 → sacamos A.
74 98 97 31 50 86 55 — Pivote: 74 (primer elemento)Estado inicial
i=0 (pivote=74), j=6
i avanza hasta >74, j retrocede hasta ≤74
i=1 (98>74) ✓ — j=6 (55≤74) ✓ — i < j → swap(98, 55)
Continuamos
i=2 (97>74) ✓ — j=5 (86>74) → j=4 (50≤74) ✓ — i < j → swap(97, 50)
i cruza a j → colocamos pivote
i avanza: i=3 (31≤74) → i=4 (97>74). j=3 (31≤74). Ahora i > j → cruzados. swap(pivote, arr[j]) = swap(74, 31)
pivote=74 en pos 0, i=1, j recorre 1→6
j=1: 98>74 → nada. j=2: 97>74 → nada. j=3: 31<74 → swap(arr[1], arr[3])
i avanza a 2
j=4: 50<74 → swap(arr[2], arr[4])
i avanza a 3
j=5: 86>74 → nada. j=6: 55<74 → swap(arr[3], arr[6])
i avanza a 4
Fin del recorrido → swap(pivote, arr[i-1]) = swap(arr[0], arr[3])
¿Qué hace Floyd?
Calcula las distancias mínimas entre todos los pares de nodos. Para cada nodo k intermedio, comprueba si ir de i→k→j es más corto que ir de i→j directamente.
Fórmula: D[i][j] = min(D[i][j], D[i][k] + D[k][j])
| a | b | c | d | |
|---|---|---|---|---|
| a | 0 | ∞ | ∞ | ∞ |
| b | 5 | 0 | ∞ | ∞ |
| c | ∞ | 6 | 0 | ∞ |
| d | ∞ | 2 | 6 | 0 |
| a | b | c | d | |
|---|---|---|---|---|
| a | 0 | ∞ | ∞ | ∞ |
| b | 5 | 0 | ∞ | ∞ |
| c | 11 | 6 | 0 | ∞ |
| d | 7 | 2 | 6 | 0 |
c→a: antes ∞, ahora c→b→a = 6+5 = 11. d→a: antes ∞, ahora d→b→a = 2+5 = 7.
b→a = 5 (directo) | c→a = 11 (c→b→a) | d→a = 7 (d→b→a)
c→b = 6 (directo) | d→b = 2 (directo) | d→c = 6 (directo)
Resto de pares: ∞ (no hay camino)
¿Cómo funciona la tabla LCS?
Si los caracteres coinciden: L[i][j] = L[i-1][j-1] + 1
Si no coinciden: L[i][j] = max(L[i-1][j], L[i][j-1])
| ε | C | A | A | C | G | T | C | G | |
|---|---|---|---|---|---|---|---|---|---|
| ε | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| T | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
| C | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 2 |
| A | 0 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
| A | 0 | 1 | 2 | 3 | 3 | 3 | 3 | 3 | 3 |
| C | 0 | 1 | 2 | 3 | 4 | 4 | 4 | 4 | 4 |
| G | 0 | 1 | 2 | 3 | 4 | 5 | 5 | 5 | 5 |
| T | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 6 | 6 |
| T | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 6 | 6 |
| A | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 6 | 6 |
Recuperación: trazar desde L[9][8]=6 hacia atrás buscando las coincidencias marcadas en morado.
Fórmula 0/1 (cada objeto máximo una vez)
M[i][w] = M[i-1][w] si peso[i] > w (no cabe)M[i][w] = max(M[i-1][w], M[i-1][w-peso[i]] + val[i]) si cabe
| Obj\Cap | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1(p3,v15) | 0 | 0 | 0 | 15 | 15 | 15 | 15 | 15 | 15 | 15 | 15 |
| 2(p4,v16) | 0 | 0 | 0 | 15 | 16 | 16 | 16 | 31 | 31 | 31 | 31 |
| 3(p1,v13) | 0 | 13 | 13 | 15 | 28 | 29 | 29 | 31 | 44 | 44 | 44 |
| 4(p3,v15) | 0 | 13 | 13 | 15 | 28 | 29 | 30 | 31 | 44 | 46 | 46 |
Recuperación de objetos (trazar hacia atrás desde M[4][10]=46)
M[4][10]=46 ≠ M[3][10]=44 → objeto 4 incluido (p=3, v=15; nuevo w=10−3=7)
M[3][7]=31 = M[2][7]=31 → objeto 3 NO incluido (w queda en 7)
M[2][7]=31 ≠ M[1][7]=15 → objeto 2 incluido (p=4, v=16; nuevo w=7−4=3)
M[1][3]=15 ≠ M[0][3]=0 → objeto 1 incluido (p=3, v=15; nuevo w=3−3=0)
M[0][0]=0 → fin
Pesos: 3 + 4 + 3 = 10 ≤ 10 ✓
Valor total: 15 + 16 + 15 = 46
Verificación de alternativas:
Obj 1+2+3: peso 3+4+1=8, valor 15+16+13=44 < 46
Obj 2+3+4: peso 4+1+3=8, valor 16+13+15=44 < 46
Obj 1+3+4: peso 3+1+3=7, valor 15+13+15=43 < 46
Obj 1+2+3+4: peso 11 > 10 ❌ no cabe
17, 52, 71, 92, 98, 38 sobre un montículo mínimo inicialmente vacío. Sobre el montículo resultante, realice la operación eliminar tres veces.Regla de inserción en min-heap
Se inserta al final (último nivel, de izquierda a derecha) y se hace sift-up: se compara el nodo con su padre; si es menor, se intercambian. Se repite hasta que el padre sea menor o se llegue a la raíz.
Regla de eliminación del mínimo: Se extrae la raíz, se coloca el último elemento en su lugar, y se hace sift-down: se intercambia con el hijo menor hasta recuperar la propiedad.
Insertar 17
Montículo vacío → 17 es la raíz. Sin sift-up necesario.
Array: [17]
Insertar 52
Se inserta a la derecha de 17. Padre de pos 1 = pos 0 → 17. 52 ≥ 17 → sin intercambio.
Array: [17, 52]
Insertar 71
Se inserta en pos 2 (hijo derecho de 17). Padre = 17. 71 ≥ 17 → sin intercambio.
Array: [17, 52, 71]
Insertar 92
Pos 3 = hijo izquierdo de 52. Padre = 52. 92 ≥ 52 → sin intercambio.
Array: [17, 52, 71, 92]
Insertar 98
Pos 4 = hijo derecho de 52. Padre = 52. 98 ≥ 52 → sin intercambio.
Array: [17, 52, 71, 92, 98]
Insertar 38 — ¡Requiere sift-up!
Pos 5 = hijo izquierdo de 71. Padre = 71. 38 < 71 → intercambio(38, 71).
Ahora pos 2, padre = 17. 38 ≥ 17 → fin.
Array final: [17, 52, 38, 92, 98, 71]
Árbol: raíz=17, hijos de 17: 52(izq) y 38(der). Hijos de 52: 92(izq) y 98(der). Hijos de 38: 71(izq).
Eliminar mínimo (17)
Extraemos la raíz (17). El último elemento (71) pasa a la raíz. Sift-down: hijos de 71 son 52 y 38. Mínimo hijo = 38. 38 < 71 → intercambio(71, 38). 71 baja a pos 2, su único hijo es 71 mismo (pos 5), pero ya no tiene hijos → fin.
Extraído: 17 | Array: [38, 52, 71, 92, 98]
Eliminar mínimo (38)
Extraemos 38. El último (98) pasa a raíz. Hijos: 52(izq) y 71(der). Mínimo = 52. 52 < 98 → intercambio(98, 52). 98 baja a pos 1, hijos: 92(izq). 92 < 98 → intercambio(98, 92). 98 en pos 3, sin hijos → fin.
Extraído: 38 | Array: [52, 92, 71, 98]
Eliminar mínimo (52)
Extraemos 52. El último (98) pasa a raíz. Hijos: 92(izq) y 71(der). Mínimo = 71. 71 < 98 → intercambio(98, 71). 98 baja a pos 2, sin hijos → fin.
Extraído: 52 | Array: [71, 92, 98]
Montículo resultante tras 3 eliminaciones: [71, 92, 98]
Condiciones que debe cumplir un max-heap de 6 nodos
Estructura fija: con 6 nodos, la forma del árbol siempre es la misma (completo por niveles): raíz, 2 hijos, 4 nietos de los cuales el último nivel tiene 3 ocupados (izq, centro-izq, centro-der de la rama izquierda).
Propiedad de montículo máximo: cada padre ≥ sus hijos.
Con los valores {1,1,2,2,3,3}, la raíz debe ser 3 (máximo). A continuación se enumeran todas las asignaciones válidas.
Raíz (pos 0): siempre 3
El máximo del conjunto es 3, y debe ir en la raíz. Nos quedan {1,1,2,2,3} para las 5 posiciones restantes.
Hijos de la raíz (pos 1 y pos 2): deben ser ≤ 3. El segundo 3 puede estar en pos 1 o pos 2. Los 2s también pueden estar en esas posiciones. Analizamos caso por caso:
Raíz siempre = 3. El segundo 3 puede ir en pos 1 (izq) o pos 2 (der). Para cada caso, los 2s pueden ocupar las posiciones de nivel 2 disponibles, con los 1s en el resto. Dado que hay 2 copias de cada valor, se generan las 6 combinaciones estructuralmente distintas mostradas.
Condiciones de un AVL con 7 nodos y raíz ≥ 4
AVL: árbol BST donde |h_izq − h_der| ≤ 1 en cada nodo.
Con 7 nodos: la única forma AVL perfectamente balanceada es el árbol completo de altura 3 (raíz + 2 hijos + 4 nietos). Factor de equilibrio = 0 en todos.
BST: todos los valores del subárbol izquierdo < raíz < todos los del subárbol derecho.
Raíces posibles: 4, 5, 6, 7 (pero raíz = 7 dejaría 6 nodos todos a la izquierda → no AVL). Veamos:
¿Qué raíces son viables?
Para que el árbol sea AVL con 7 nodos, el subárbol izquierdo y el derecho deben tener alturas que difieran en ≤1. Con 7 nodos y equilibrio perfecto: izquierda=3 nodos, derecha=3 nodos (árbol completo).
— Raíz = 4: izq={1,2,3} (3 nodos), der={5,6,7} (3 nodos) ✅
— Raíz = 5: izq={1,2,3,4} (4 nodos), der={6,7} (2 nodos) → alturas 2 vs 1 → FE=+1 ✅ (válido AVL)
— Raíz = 6: izq={1,2,3,4,5} (5 nodos), der={7} (1 nodo) → alturas 2 vs 0 → FE=+2 ❌
— Raíz = 7: izq={1,2,3,4,5,6} (6 nodos), der=∅ → FE=+3 ❌
Raíces válidas: 4 y 5.
Izquierda: {1,2,3} → raíz del subárbol izq = 2. Derecha: {5,6,7} → raíz del subárbol der = 6. Es el único AVL perfecto con raíz 4.
Izq={1,2,3,4} con 4 nodos, Der={6,7} con 2 nodos. El subárbol izquierdo tiene h=2 y el derecho h=1 → FE(raíz)=+1 ✅. Para {1,2,3,4} hay 4 AVLs posibles con raíces 2 o 3; para {6,7} solo hay uno (raíz=6, hijo der=7).
• Raíz = 4: 1 árbol (perfecto, completamente simétrico)
• Raíz = 5: 2 árboles (subárbol izq con raíz 2 o raíz 3; subárbol der siempre 6→7)
• Raíz = 6: ❌ no válido (FE=+2 en la raíz)
• Raíz = 7: ❌ no válido (FE=+3 en la raíz)
TOTAL: 3 árboles AVL válidos
Notación
V = número de vértices (nodos) | E = número de arcos (aristas) | deg(v) = grado del nodo v
| Operación | Matriz de adyacencia | Listas de adyacencia |
|---|---|---|
| ¿Hay arco (u, v)? | O(1) | O(deg(u)) |
| Añadir arco (u, v) | O(1) | O(1) |
| Añadir un nodo | O(V²) | O(1) |
| Eliminar un nodo | O(V²) | O(V + E) |
¿Hay arco (u, v)?
Matriz: acceso directo M[u][v] → O(1).
Listas: hay que recorrer la lista de vecinos de u hasta encontrar v (o no). En el peor caso, u tiene todos los vértices como vecinos → O(deg(u)), que puede ser O(V).
Añadir arco (u, v)
Matriz: M[u][v] = 1 (y M[v][u]=1 si no dirigido) → O(1).
Listas: insertar v al principio de la lista de u (y viceversa) → O(1).
Añadir un nodo
Matriz: es necesario ampliar la matriz de V×V a (V+1)×(V+1), copiando o reasignando toda la estructura → O(V²).
Listas: simplemente añadir una nueva entrada vacía a la lista de listas → O(1).
Eliminar un nodo
Matriz: hay que eliminar la fila y columna del nodo, y reorganizar la matriz → O(V²).
Listas: hay que eliminar la lista del nodo y también todas las referencias a ese nodo en las listas de sus vecinos. En el peor caso (grafo denso), esto implica revisar todas las listas → O(V + E).
Espacio: Matriz = O(V²) | Listas = O(V + E)
Idea central
Dijkstra mantiene una tabla de distancias mínimas conocidas desde el origen. En cada iteración, selecciona el nodo no visitado con menor distancia, lo marca como visitado y actualiza ("relaja") las distancias de sus vecinos. Solo funciona con pesos no negativos.
| Iteración | Nodo visitado | dist[A] | dist[B] | dist[C] | dist[D] | dist[E] |
|---|---|---|---|---|---|---|
| Inicio | — | 0 | ∞ | ∞ | ∞ | ∞ |
| 1 | A (dist=0) | 0 ✓ | 4 | 2 | ∞ | ∞ |
| 2 | C (dist=2) | 0 ✓ | 3 | 2 ✓ | 10 | 12 |
| 3 | B (dist=3) | 0 ✓ | 3 ✓ | 2 ✓ | 8 | 12 |
| 4 | D (dist=8) | 0 ✓ | 3 ✓ | 2 ✓ | 8 ✓ | 10 |
| 5 | E (dist=10) | 0 ✓ | 3 ✓ | 2 ✓ | 8 ✓ | 10 ✓ |
Visitar A (dist=0)
A es el origen. Relajamos sus vecinos: B = 0+4 = 4, C = 0+2 = 2. Ambos mejoran respecto a ∞. A queda marcado como visitado.
Visitar C (dist=2, mínimo no visitado)
Vecinos de C: B → min(4, 2+1) = 3 ✓ mejora. D → min(∞, 2+8) = 10. E → min(∞, 2+10) = 12.
Visitar B (dist=3, mínimo no visitado)
Vecinos de B: D → min(10, 3+5) = 8 ✓ mejora. E no es vecino directo de B. B queda visitado.
Visitar D (dist=8)
Vecinos de D: E → min(12, 8+2) = 10 ✓ mejora. D queda visitado.
Visitar E (dist=10) — fin
E no tiene vecinos sin visitar. Algoritmo completado.
A→A = 0 | A→B = 3 (ruta: A→C→B) | A→C = 2 (ruta: A→C) | A→D = 8 (ruta: A→C→B→D) | A→E = 10 (ruta: A→C→B→D→E)
Complejidad: O((V + E) log V) con cola de prioridad | O(V²) con tabla simple