En esta lección fijamos las bases de la complejidad algorítmica y de la notación Big-O. El objetivo es entender qué medimos, por qué lo hacemos y cómo impacta en el código que escribimos en C.
La complejidad describe cómo crece el consumo de recursos a medida que aumenta el tamaño de entrada n. Nos enfocamos en:
O(f(n)).O(f(n)) para distinguir si es constante, lineal o mayor.La notación Big-O expresa la cota superior asintótica, es decir, el ritmo de crecimiento dominante a grandes n.
Medir la complejidad permite tomar decisiones de diseño informadas:
Sin esta mirada, es fácil elegir una solución que funcione en casos pequeños pero colapse en producción.
El análisis asintótico ignora constantes y asume un modelo ideal; el tiempo real depende de hardware y del entorno. Dos ejemplos:
O(n) con constantes grandes puede tardar más que uno O(n log n) para tamaños pequeños.Podemos medir en C con un bucle simple y contadores de pasos:
long contar_pasadas(const int *datos, int n) {
long pasos = 0;
for (int i = 0; i < n; i++) {
pasos++; // lectura del dato
if (datos[i] % 2 == 0) {
pasos++; // comparación extra
}
}
return pasos; // modelo teórico de pasos ejecutados
}
El código refleja un modelo de pasos. Para tiempo real usaríamos temporizadores del sistema, pero el orden de crecimiento sigue siendo O(n).
Elegir un modelo aclara qué operaciones cuentan como un paso:
En este tutorial partimos del modelo RAM y señalamos cuando otros modelos cambian las conclusiones.
Trabajar en C expone los costos de tiempo y espacio sin abstracciones intermedias:
malloc y free permite ajustar el uso espacial pero introduce riesgos de fugas.Estas ideas guiarán los temas siguientes, donde profundizaremos en la notación, los tipos de complejidad temporal y espacial, y las formas de medirlos en práctica.