← Martes 25 — Análisis y notación asintótica
Pregunta central
¿Cómo convierte una buena representación de datos el pseudocódigo de Gale–Shapley en un algoritmo y qué patrones producen los tiempos , , , , y exponencial?
Respuesta corta
El número de iteraciones no basta: hay que controlar el costo de cada operación. En Gale–Shapley, arreglos de parejas, una cola de hospitales libres, apuntadores
nexty tablas inversasrankhacen que cada propuesta cueste . Como hay propuestas y el preprocesamiento cuesta , el total es . Los demás ejemplos muestran que explotar orden, invariantes y descomposición reduce drásticamente el espacio de búsqueda.
Mapa de la clase
flowchart TB GS["Pseudocódigo Gale–Shapley"] --> DS["Elegir estructuras de datos"] DS --> P["Cada propuesta: O(1)"] P --> TOTAL["O(n²) propuestas ⇒ Θ(n²)"] TOTAL --> CAT["Catálogo de crecimientos"] CAT --> RED["Reducir candidatos"] CAT --> ORD["Explotar orden"] CAT --> DIV["Dividir el problema"] RED --> FAST["Mejores algoritmos"] ORD --> FAST DIV --> FAST
1. Implementación eficiente de Gale–Shapley
La versión conceptual es:
GALE–SHAPLEY(preferencias de n hospitales y n estudiantes)
M ← ∅
mientras exista un hospital h libre:
s ← estudiante favorita de h a quien aún no propone
si s está libre:
agregar (h, s) a M
si no, si s prefiere h sobre su pareja h':
reemplazar (h', s) por (h, s)
en otro caso:
s rechaza a h
devolver MDe la clase anterior sabemos que ninguna pareja hospital–estudiante recibe dos propuestas. Por eso hay a lo sumo . Pero esto solo prueba un total si encontrar y procesar cada propuesta cuesta .
Paso 1: representar el emparejamiento
Se indexan hospitales y estudiantes de a y se guardan las parejas en dos arreglos:
student[h] = s: estudiante emparejada con ;hospital[s] = h: hospital emparejado con ;- el valor
0significa “libre”.
Así, consultar, agregar, quitar o reemplazar una pareja modifica un número constante de celdas:
Paso 2: encontrar un hospital libre
Mantener los hospitales libres en una cola o pila evita recorrer el arreglo completo en cada iteración.
Paso 3: encontrar la siguiente propuesta
Para cada hospital se guarda:
prefH[h]: su lista ordenada de estudiantes;next[h]: índice de la siguiente estudiante a quien no ha propuesto.
La siguiente candidata es
s ← prefH[h][next[h]]
next[h] ← next[h] + 1El apuntador solo avanza; nunca vuelve a examinar una propuesta anterior.
Paso 4: comparar preferencias con una tabla inversa
Supongamos que una estudiante guarda esta lista:
| Posición | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
pref[i] | 8 | 3 | 7 | 1 | 4 | 5 | 6 | 2 |
Buscar linealmente la posición de un hospital costaría por comparación. Se construye una lista inversa:
para i ← 1 hasta n:
rank[pref[i]] ← iEl resultado es:
| Hospital | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
rank[h] | 4 | 8 | 2 | 5 | 6 | 7 | 3 | 1 |
Ahora una comparación se vuelve una desigualdad entre dos accesos directos:
Por ejemplo, rank[4] = 5 < rank[6] = 7, así que la estudiante prefiere el hospital 4 sobre el 6.
La cuenta completa, paso a paso
| Necesidad | Representación | Costo |
|---|---|---|
| Encontrar hospital libre | Cola o pila | |
| Consultar pareja de | student[h] | |
| Consultar pareja de | hospital[s] | |
| Obtener siguiente propuesta | prefH[h] + next[h] | |
| Comparar dos hospitales para | rankS[s][h] | |
| Cambiar una pareja | Actualizar ambos arreglos |
Análisis total
- Construir tablas
rankde longitud cuesta . - Hay a lo sumo propuestas.
- Procesar una propuesta cuesta .
Por tanto,
La presentación también afirma una cota inferior: en el peor caso, cualquier algoritmo que encuentre un emparejamiento estable debe consultar posiciones de las preferencias. Junto con la implementación:
Idea transferible
Una tabla de preprocesamiento puede pagar una sola vez para convertir hasta consultas de costo en consultas de costo . Sin
rank, el análisis ingenuo podría subir hasta .
2. Familias comunes de tiempos de ejecución
Mueve para observar por qué las familias polinomiales y las exponenciales terminan separándose enormemente. Selecciona una fila para ver el patrón algorítmico que produce ese crecimiento.
| Orden | Ejemplo de las diapositivas | Patrón principal |
|---|---|---|
Acceder a A[i] | Una cantidad fija de operaciones | |
| Búsqueda binaria | Eliminar una fracción constante | |
| Mezcla; TARGET-SUM | Recorrer cada elemento pocas veces | |
| Mergesort; mayor intervalo vacío | niveles con trabajo lineal | |
| Enumerar pares; 3-SUM mejorado | Dos decisiones de tamaño | |
| 3-SUM directo | Enumerar ternas | |
| Conjunto independiente de tamaño fijo | Enumerar subconjuntos de tamaño constante | |
| Exponencial | Conjunto independiente máximo; TSP exhaustivo | Enumerar subconjuntos o permutaciones |
: tiempo constante
El número de operaciones está acotado por una constante que no depende de . En word RAM, ejemplos habituales son:
- una rama condicional;
- una operación aritmética/lógica sobre una palabra;
- declarar o inicializar una variable;
- seguir un enlace;
- acceder a
A[i]; - comparar o intercambiar dos posiciones.
Constante no significa instantáneo
Una operación puede tardar 1 o 10 000 unidades y seguir siendo si esa cantidad no crece con .
3. Tiempo lineal:
Mezclar dos listas ordenadas
Sean y dos listas ordenadas. Se comparan sus primeros elementos pendientes y se extrae el menor.
i ← 1; j ← 1
mientras ambas listas tengan elementos:
si A[i] ≤ B[j]: anexar A[i]; i ← i + 1
en otro caso: anexar B[j]; j ← j + 1
anexar el resto de la lista no vacíaCada iteración consume definitivamente un elemento. Con elementos, se hacen a lo sumo comparaciones:
TARGET-SUM con dos apuntadores
Dado un arreglo ordenado de enteros distintos y un objetivo , queremos dos valores cuya suma sea .
i ← 1
j ← n
mientras i < j:
s ← A[i] + A[j]
si s = T: devolver (A[i], A[j])
si s < T: i ← i + 1
si s > T: j ← j - 1
devolver "no existe"flowchart TB C["comparar A[i] + A[j] con T"] -->|"igual"| F["encontrado"] C -->|"menor"| I["incrementar i"] C -->|"mayor"| J["decrementar j"] I --> C J --> C
Invariante: si existe una solución, ninguna usa una posición que ya quedó a la izquierda de o a la derecha de .
Por qué es seguro mover un apuntador:
- Si , emparejar con cualquier elemento entre y solo produce una suma menor o igual; se descarta.
- Si , emparejar con cualquier elemento entre y solo produce una suma mayor o igual; se descarta.
Cada paso reduce el intervalo en una posición, así que hay pasos. Probar todos los pares habría costado .
4. Tiempo logarítmico:
Búsqueda binaria
lo ← 1; hi ← n
mientras lo ≤ hi:
mid ← ⌊(lo + hi) / 2⌋
si x < A[mid]: hi ← mid - 1
si x > A[mid]: lo ← mid + 1
en otro caso: devolver mid
devolver -1Invariante: si está en el arreglo, entonces está dentro de .
Después de iteraciones quedan a lo sumo
candidatos. Para llegar a uno:
Por tanto, .
Arreglo ordenado y rotado
Ejemplo:
[80, 85, 90, 95, 20, 30, 35, 50, 60, 65, 67, 75]La diapositiva propone:
- Encontrar en el índice del elemento más pequeño.
- Aplicar búsqueda binaria en o .
Para localizar el mínimo se mantiene el invariante mientras el intervalo contiene la ruptura. Comparar A[mid] con A[hi] determina qué mitad la contiene.
La suma sigue siendo logarítmica:
5. Tiempo lineal-logarítmico:
Mergesort
Mergesort divide el arreglo por la mitad hasta llegar a subarreglos unitarios y luego mezcla resultados ordenados.
flowchart TB A["n elementos"] --> L["n/2"] A --> R["n/2"] L --> LL["n/4"] L --> LR["n/4"] R --> RL["n/4"] R --> RR["n/4"] LL --> COST["trabajo total por nivel: Θ(n)"] LR --> COST RL --> COST RR --> COST COST --> TOTAL["log₂ n niveles ⇒ Θ(n log n)"]
La profundidad es porque el tamaño se divide entre dos en cada nivel; la mezcla procesa elementos por nivel.
Mayor intervalo vacío
Dadas marcas de tiempo , se busca el intervalo más largo sin llegadas.
- Ordenar las marcas: .
- Recorrer diferencias consecutivas: .
- Conservar la máxima diferencia: por elemento.
Por la regla de sumas,
6. Tiempo cuadrático y cúbico
Par de puntos más cercano
Enumerar todos los pares con examina
candidatos. La diapositiva advierte que esta aparente necesidad es una ilusión: existe un algoritmo mediante divide y vencerás. Una estrategia obvia no demuestra una cota inferior del problema.
3-SUM directo:
para i ← 1 hasta n:
para j ← i + 1 hasta n:
para k ← j + 1 hasta n:
si A[i] + A[j] + A[k] = 0:
devolver la ternaSe enumeran ternas.
3-SUM mejorado:
- Ordenar en .
- Para cada , resolver TARGET-SUM con objetivo sin reutilizar .
- Cada ejecución de dos apuntadores cuesta y se repite veces.
Patrón de mejora
Cambiar “tres elecciones independientes” por “una elección + un subproblema lineal” elimina un factor .
La diapositiva menciona una mejora teórica subcuadrática por factores logarítmicos y la conjetura de que no existe un algoritmo para ninguna constante .
7. Polinomial frente a exponencial
Conjunto independiente de tamaño fijo
Si es una constante, se pueden enumerar todos los subconjuntos de vértices y verificar cada uno:
Para esto es polinomial, aunque probablemente no sea práctico.
Conjunto independiente máximo
Si el tamaño ya no está fijado, hay que considerar todos los subconjuntos del conjunto de vértices:
Verificar cada subconjunto de manera directa lleva al algoritmo de la diapositiva.
TSP euclidiano por fuerza bruta
Enumerar los órdenes de visita y calcular la longitud de cada recorrido cuesta
Como
el crecimiento queda muy lejos del tiempo polinomial.
Convención de las diapositivas
Las diapositivas usan tiempo exponencial en el sentido amplio
Con esta convención, , y quedan incluidos, pero ninguna de estas opciones es equivalente por sí sola:
- excluye, por ejemplo, ;
- para alguna constante incluye , pero excluye .
Por eso la respuesta del quiz 4 es D: ninguna.
Método práctico para analizar pseudocódigo
flowchart TB A["1. Definir el tamaño"] --> B["2. Fijar operaciones primitivas"] B --> C["3. Contar iteraciones"] C --> D["4. Multiplicar bloques anidados"] D --> E["5. Sumar bloques consecutivos"] E --> F["6. Incluir el costo de las estructuras"] F --> G["7. Simplificar con O, Ω o Θ"] G --> H["8. Buscar orden o invariantes desaprovechados"]
Atajos que deben justificarse:
- ciclo que avanza de uno en uno hasta : ;
- ciclo que duplica o divide el índice: ;
- dos ciclos independientes de longitud : usualmente ;
- enumerar subconjuntos: ;
- enumerar permutaciones: ;
- ordenar y luego recorrer: .
No todos los ciclos anidados son automáticamente cuadráticos. Por ejemplo,
para i ← 1 hasta n:
j ← 1
mientras j ≤ n:
j ← 2jrealiza veces un ciclo de , por lo que cuesta .
Errores frecuentes
- Concluir para Gale–Shapley solo porque hay propuestas, sin analizar el costo de encontrarlas y procesarlas.
- Recorrer la lista de preferencias para cada comparación en vez de construir
rank. - Suponer que dos ciclos visualmente anidados siempre producen iteraciones.
- Olvidar el costo de ordenar antes de aplicar dos apuntadores.
- Confundir una cota de un algoritmo ingenuo con una cota inferior del problema.
- Creer que es polinomial cuando crece como parte de la entrada; la definición exige constante.
- Llamar a simplemente ; crece más rápido.
Autoevaluación
- Puedo explicar el propósito de
student,hospital,nextyrank. - Puedo derivar para Gale–Shapley, incluyendo el preprocesamiento.
- Puedo demostrar el invariante de TARGET-SUM y su costo lineal.
- Puedo explicar por qué búsqueda binaria tarda .
- Puedo derivar para mergesort por niveles.
- Puedo transformar 3-SUM de a .
- Puedo distinguir enumerar subconjuntos de tamaño fijo, todos los subconjuntos y todas las permutaciones.
Resumen después de clase
La eficiencia de una implementación depende tanto del algoritmo como de la representación. Gale–Shapley alcanza porque preprocesa las preferencias y convierte cada propuesta en una secuencia de accesos directos. El catálogo de tiempos muestra patrones reutilizables: dos apuntadores explotan orden para lograr tiempo lineal; la búsqueda binaria reduce candidatos a la mitad; mergesort combina niveles con trabajo lineal; y la fuerza bruta sobre pares, ternas, subconjuntos o permutaciones produce crecimiento cuadrático, cúbico o exponencial. El principio general es buscar estructura antes de enumerar posibilidades.
Referencias
- Kevin Wayne, Algorithm Analysis, diapositivas 25–49, actualización del 16 de diciembre de 2021.
- Jon Kleinberg y Éva Tardos, Algorithm Design, capítulo 2.
- Conexión previa: Gale–Shapley: corrección y optimalidad.