El punto donde las dos curvas comienzan a separarse es ( x0 ). A partir de este valor, se cumple que ( f(x) <= cg(x) ) para todos los valores de ( x >= 0 ). Esto significa que para valores grandes de ( x ), el crecimiento de ( f(x) ) está acotado superiormente por ( cg(x) ).
Notación en Big O | Nombre de la función |
---|---|
O(1) | Constante |
O(log n) | Logarítmica |
O(n) | Lineal |
O(n · log n) | Lineal logarítmica o casi-lineal |
O(n^2) | Cuadrática |
O(n^k) | Potencial (k siendo constante y k > 1) |
O(k^n) | Exponencial (k usualmente siendo 2 y n > 1) |
O(n!) | Factorial |
Horrible |
Bad |
Fair |
Good |
Excellent |
Notación | Tipo de cota | Descripción |
---|---|---|
O (Big O) | Cota asintótica superior (≥) | Describe el peor de los casos de un algoritmo. |
o (small o) | Límite superior estricto (>) | Una función crece más lentamente que otra función . |
Ω (Big Omega) | Cota asintótica inferior (≤) | Describe el mejor de los casos de un algoritmo. |
ω (small omega) | Límite inferior estricto (<) | Una función crece más rápidamente que otra función. |
Θ (Big Theta) | Cota asintótica exacta (==) | Describe el caso promedio de un algoritmo. |
Para determinar la complejidad temporal de un algoritmo, se analiza el tiempo de ejecución en función del tamaño de la entrada n sumando las complejidades de cada operación principal. Luego, se simplifica la expresión combinando términos y eliminando constantes y términos de menor orden, enfocándose en el término dominante que crece más rápido respecto a n
.
Los pasos para realizar un análisis de la complejidad son:
int n=1000; //es O(1), ya que n ya esta declarada
if(n%2==0) //O(1)
cout<<"par"; //O(1)
else //O(1)
cout<<"impar"; //O(1)
Complejidad = 1 + 1 + 1 + 1 + 1 = O(5) = O(1);
int n=0; // O(1)
cin>>n; // O(1)
for(int i=0;i<n;i++){ //es O(n) ya que n es el limite
if(i%2==0) // O(n)
cout<<i<<" es par"; // O(n)
else // O(n)
cout<<i<<" es impar";// O(n)
}
Complejidad = 1 + 1 + n + n + n + n + n = O(2 + 5n) = O(n);
int n=0, j=0; //O(1)
for(int i=0;i<n;i++){ //O(n)
if(i%2==0) //O(n)
cout<<i<<" es par"; //O(n)
else //O(n)
cout<<i<<" es impar"; //O(n)
}
while(j<n){ //O(n)
if(i%3==0) //O(n)
cout<<i<<" es mutliplo de 3"; //O(n)
else //O(n)
cout<<i<<" no es multimplo d"; //O(n)
j++; //O(n)
}
Complejidad = 1 + n + n + ... + n = O(1+ 11n) = O(n)
int n=0; //O(1)
cin>>n; //O(1)
for(int i=0;i<n;i*=2){ //O(log (n)) ya incrementa con multiplicaciones en lugar de sumas
if(i%2==0) //O(log (n))
cout<<i<<" es par"; //O(log (n))
else //O(log (n))
cout<<i<<" es impar"; //O(log (n))
}
Complejidad = 1 + 1 + log(n) + log(n) + log(n) + log(n) + log(n) = O(2 + 6log(n)) = O(log(n))
int n=0; //O(1)
cin>>n; //O(1)
for(int i=0;i<n;i++){ //O(n)
for(int j=0;j<n;j++){ //O(n^2)
cout<<i<<j<<endl; //O(n^2)
}
}
Complejidad = 1 + 1 + n + n * n + n^2 = O(2 + n + 2n^2) = O(n^2)
int n=0; //O(1)
cin>>n; //O(1)
for(int i=0;i<n;i++) //O(n)
for(int j=0;j<n;j++) //O(n^2)
for(int ca=0;ca<n;ca++) //O(n^3)
for(int cb=0;cb<n;cb++) //O(n^4)
... //O(n^5)
... //O(n^6)
for(int k=0;k<n;k++) //O(n^7)
cout << i << j << ca << cb << ... << ... << k; //O(n^k)
Complejidad = 1 + 1 + n + n * n + n^3 ... + n^k = O(2 + n + n^2 + ... n^k) = O(n^k)
int n=0; //O(1)
cin>>n; //O(1)
for(int j=0;j<n;j++){ //O(n)
for(int i=0;i<n;i*=2){ //O(n(log(n)))
if(i%2==0) //O(n(log(n)))
cout<<i<<" es par"; //O(n(log(n)))
else //O(n(log(n)))
cout<<i<<" es impar"; //O(n(log(n)))
}
}
Complejidad = 1 + 1 + n + n * log(n) + n(log(n)) + n(log(n)) + n(log(n)) + n(log(n))
= O(2 + n + 5n(log(n))) = O(nlog(n))
Muchos algoritmos recursivos tienen una complejidad de O(k^n), donde k
es el número de llamadas recursivas en cada nivel de la recursión y n
es la profundidad de la recursión. Esto es común en algoritmos que se pueden representar como un árbol de recursión, como lo seria el cálculo de la secuencia de Fibonacci.
Ejemplo:
int fibonacci(int n){ //O(2^n)
if(n<=1) //O(1)
return 1; //O(1)
return fibonacci(n-1) + fibonacci(n-2); //O(2^n)
}
n = 5
La complejidad en el espacio mide la cantidad de memoria que un algoritmo requiere en función del tamaño de la entrada. Es un aspecto crucial del análisis de algoritmos, para evaluar la eficiencia de un algoritmo.
int a = 2; //O(1) de espacio
int n; cin >> n; //O(1) de espacio
int* vec = new int[n]; //O(n) de espacio
vector<int> v(n); //O(n) de espacio
vector<vector<int>> mat(n,vector<int>(n)); //O(n^2) de espacio
int** matrix = new int*[n]; //O(n) de espacio
for (int i = 0; i < n; ++i)
matrix[i] = new int[n];//O(n^2) de espacio
string entrada;
cin>>entrada;
int x=5;
if(entrada=="holi")
cout << x;
int n;
cin>>n;
for (int i=1; i<=n; i++)
cout << "hola";
string entrada; // O(1)
cin>>entrada; // O(1)
int x=5; // O(1)
if(entrada=="holi") // O(1)
cout<<x; // O(1)
int n; //O(1)
cin>>n; //O(1)
for (int i=1; i<=n; i++) //O(n)
cout<<"hola"; //O(n)
int n, c=5; cin>>n;
for (int i=1; i<=n; i+=c)
for (int j=1; j<=n; j+=c)
cout<<i+j;
int n;in>>n;
n=2;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k*=j)
cout<<i*j*k;
int n, c=5; cin>>n; //O(1)
for (int i=1; i<=n; i+=c) //O(n)
for (int j=1; j<=n; j+=c) //O(n^2)
cout<<i+j; //O(n^2)
int n; //O(1)
cin>>n; //O(1)
n=2; //O(1)
for(int i=0;i<n;i++) //O(1)
for(int j=0;j<n;j++) //O(1)
for(int k=0;k<n;k*=j) //O(1)
cout<<i*j*k; //O(1)
int n,c=2;
cin>>n;
for(int i=0;i<n;i*=c){
cout<<i;
}
int n,c=5,i=10;
cin>>n;
for(i=0;i<n;pow(i, c))
cout<<i;
int n,c=2; //O(1)
cin>>n; //O(1)
for(int i=0;i<n;i*=c){ //O(log(n))
cout<<i; //O(log(n))
}
int n,c=5,i=10; //O(1)
cin>>n; //O(1)
for(i=0;i<n;pow(i, c)) //O(log(log(n)))
cout<<i; //O(log(log(n)))
Resuelve los siguientes problemas escribiendo la complejidad de espacio y tiempo en notación de Big O
esto es una broma, no ocupas leer la diapositiva xD
Preguntar si se acuerdan de calculo de la prepa
Comenta que si en este for fuera `j<i` sigue siendo cuadratica pero seria O((n^2)/2). como cuando imprimen un triangulo con `*`