Вы находитесь на странице: 1из 30

ANÁLISIS DE COMPLEJIDAD DE

ALGORITMOS
Karim Guevara Puente de la Vega
Agenda
 Evaluando el rendimiento
 Conteo de sentencias
 Notación O-Grande
 Caso peor, mejor, medio
 Tipos de algoritmos
 Reglas de notación asintótica
 Complejidad de algoritmos iterativos
 Complejidad de algoritmos recursivos
Introducción
 Cuando hay necesidad de elegir entre varios algoritmos,
¿cómo evaluar y/o comparar las alternativas?...
 Con frecuencia interesa el buen rendimiento
• Tiempo esperado y el uso de la memoria

• Considerar que sea fácil de implementar, verificar, mantener el código.

• Asegurar que la complejidad valga la pena.


Evaluando el rendimiento
 A posteriori (empírico)
 Se prueba con datos reales
 Implementación del algoritmo en un computador, se corrige el
código
 Sujeto a variables (hw, so, etc.)
 A priori (teórico)
 Análisis sin implementar el código
 Conjunto abstracto, independiente de cualquier entorno
 Los resultados empíricos pueden no coincidir exactamente
(especialmente para las entradas de tamaño pequeño) con un
entorno específico
¿Complejidad algorítmica?
 La eficiencia de un algoritmo puede ser cuantificada con las
siguientes medidas de complejidad:
 Complejidad Temporal o Tiempo de ejecución: Tiempo de
cómputo necesario para ejecutar algún programa.
 Complejidad Espacial: Memoria que utiliza un programa para su
ejecución

 El análisis se basa en las Complejidades Temporales, para


cada problema determinaremos una medida n (tamaño de la
entrada).
Conteo de sentencias

public double CtoF (double cTemp) {


return cTemp * 9.0 / 5.0 + 32;
}

 Cada sentencia tiene un costo de 1c


 Multiplicación, división, suma, retorno
 Total = 4c
 Valor de la entrada es importante?
Más de conteo de sentencias

public double Average (int v[]) {


int sum = 0;
for (int i = 0; i < v.length; i++)
sum += v[i];
return sum/v.length;
}

 Contando las sentencias


 Fuera bucle: 4 sentencias (inic. sum, inic. i, división, retorno)
 Cuerpo bucle: 3 sentencias (evaluación, agregación, incr. i) por elemento
 Total = 3N + 4
 ¿La entrada importa?
 Duplica el tamaño del vector – como cambia el tiempo requerido?
Más de conteo de sentencias
public double GetExtremes (int v[], int r[]) {
r[0] = r[1] = v[0];
for (int i = 1; i < v.length; i++) {
if (v[i] > r[0])
r[0] = v[i];
}
for (int i = 1; i < v.length; i++) {
if (v[i] < r[1])
r[1] = v[i];
}
}

 Bucle: evaluar i, compara, actualiza, incr. i: 4 por iteración * N


iteraciones
 2 bucles
 Fuera bucle: inic. i, inic. r
 4 + 8N
Comparando algoritmos
 Conteo de sentencia
CtoF (4) Average(3N +4) GetExtremes(8N + 4)

 GetExtremes tendrá siempre más tiempo?

 Considerar el crecimiento del patrón


 Si Average toma 2 ms. para 1000 elementos,
• Cuánto estimamos para 2000 o 10000?
 Qué de GetExtremes?
Notación O-Grande
 Resumir el conteo de sentencias
 Solo usa los términos más grandes, ignora otros, elimina todos los
coeficientes.
 Tiempo = 3n + 5  O(n)
 Tiempo = 10n - 2  O(n)
 Tiempo = 1/2n2 - n  O(n2)
 Tiempo = 2n + n3  O(2n)
 Describe la curva de crecimiento del algoritmo en el limite superior.
 Intuición: evitar detalles cuando no importan, debido a que el tamaño de
la entrada (N) es lo suficientemente grande
 Formalmente:
 O(f(n)) es un límite superior sobre el tiempo requerido
• Tiempo de ejecución – T(n) <= Cf(n) para alguna constante C y el valor de
n suficientemente grande.
Utilizando O-Grande se predice el tiempo
 Para un algoritmo O(n):
 5,000 elementos toma 3.2 segundos
 10,000 elementos toma 6.4 segundos
 20,000 elementos tomará ….?

 Para un algoritmo O(n2):


 5,000 elementos toma 2.4 segundos
 10,000 elementos toma 9.6 segundos
 20,000 elementos tomará …?.
Caso peor – mejor - medio
public boolean Search (String names[], String key) {
for (int i=0; i<names.length; i++)
if (names[i].equals(key) )
return true;
return false;
}

 Si la clave está al inicio? al medio? al final? Si no está?


 Mejor caso
 Muy rápido en algunas situaciones, a menudo no es tan relevante
  (T): orden inferior de T, u omega de T.
 Peor caso
 Límite superior de lo malo que puede suceder
 O(T): orden de complejidad de T
 Caso medio
 Media de todas las posibles entradas, puede ser más difícil de calcular con
precisión
 (T): orden exacto de T
Tiempos de ejecución: 106 instr / seg
Patrones de crecimiento
Funciones de complejidad más frecuentes
No depende del tamaño del problema
O(1) Constante Algunos algoritmos de búsqueda en Tabla
Hashing
O(log n) Logarítmica Búsqueda binaria Eficiente
Búsqueda lineal o secuencial, búsqueda en
O(n) Lineal
texto
O(n•log n) Casi lineal QuickSort

O(n 2) Cuadrática Algoritmo de la burbuja, QuickSort (peor caso)

O(n 3) Cúbica Producto de matrices Tratable

O(n k) k>3 Polinómica

Algunos algoritmos de grafos, muchos


O(k n) k>1 Exponencial problemas de optimización, por lo general en
fuerza bruta Intratable
Algunos algoritmos de grafos , todas las
O(n!) Factorial
permutaciones
Tipos de algoritmos
 Algoritmos polinomiales
 Aquellos que son proporcionales a nk
 Factibles o aplicables: son solucionables

 Algoritmos exponenciales
 Aquellos que son proporcionales a kn
 No son factibles salvo un tamaño de entrada n exageradamente
pequeño.
Reglas de notación asintótica
 Sean T1(n) y T2(n) dos funciones que expresan los tiempos
de ejecución de dos fragmentos de un programa, y se acotan
de forma que se tiene:
T1(n) = O(f1(n)) y T2(n) = O(f2(n))

 Regla de la suma
T1(n) + T2(n) = O(max(f1(n),f2(n)))

 Regla del producto


T1(n) T2(n) = O(f1(n) f2(n))
COMPLEJIDAD DE ALGORITMOS
ITERATIVOS
Instrucciones secuenciales
 Asignaciones y expresiones simples
 Tiempo de ejecución constante: O(1)

 Secuencia de instrucciones
T. ejecución =  t. ejecución individuales
 P.e.:
Sean S1 y S2, una secuencia de dos instrucciones:
T(S1 ; S2) = T(S1) + T(S2)

Aplicando la regla de la suma:


O(T(S1 ; S2)) = max(O( T(S1), T(S2) ))
Instrucciones condicionales
 SI-ENTONCES: es el tiempo necesario para evaluar la
condición, más el requerido para el conjunto de instrucciones.

T(SI-ENTONCES) = T(condición) + T(rama ENTONCES)

Aplicando la regla de la suma:


O(T(SI-ENTONCES)) =
max(O( T(condición),T(rama ENTONCES ))
Instrucciones condicionales
 SI-ENTONCES-SINO: tiempo para evaluar la condición, más
el máximo valor del conjunto de instrucciones de las ramas
ENTONCES y SINO.

T(SI-ENTONCES-SINO) = T(condición) + max(T(rama


ENTONCES), T(rama SINO))

Aplicando la regla de la suma:


O(T(SI-ENTONCES-SINO)) = O( T(condición)) +
max(O(T(rama ENTONCES )), O(T(rama SINO)))
Instrucciones de iteración
 PARA, MIENTRAS-HACER, HACER-MIENTRAS:

 Producto del número de iteraciones por la complejidad de las


instrucciones del cuerpo del mismo bucle.

 Considerar la evaluación del número de iteraciones para el peor


caso posible.

 Si existen ciclos anidados, realizar el análisis de adentro hacia


fuera.
Ejercicio

Procedimiento MatrizProd (n Por Valor, A , B, C Por Referencia)


Define i,j,k Como Entero

Para i1 Hasta n


Para j1 Hasta n
I5 C[i,j]  0;
I4 Para k1 Hasta n
I3 C[i,j] C[i,j] + A[i,k] * B[k,j];
I2 FinPara
I1 FinPara
FinPara
FinProcedimiento
Llamadas a procedimientos
 Tiempo requerido para ejecutar el cuerpo del procedimiento
llamado.
 P.e. :
Procedimiento Principal (A , B, C Por Referencia)
Define n,j,i,x Como Entero

Leer n;
i1;
Mientras i<=n Hacer
Para ji Hasta n
A[i,j] j * 2;
FinPara
i i + 1;
FinMientras
MatrizProd(n,A,B,C); O(n3)
FinProcedimiento
COMPLEJIDAD DE ALGORITMOS
RECURSIVOS
Analizando algoritmos recursivos
int factorial (int n) {
if (n < 1 )
return 1;
else
return (n * factorial(n-1));
}

 Una inspección al algoritmo puede resultar en una función de


recurrencia (relación de recurrencia):
 Imita el flujo de control dentro del algoritmo.
 Una vez obtenida esta función se puede aplicar alguna técnica:
 Recurrencias homogéneas
 Recurrencias no homogéneas
 Cambio de variables, etc.
Función de recurrencia
int factorial (int n) {
if (n < 1 )
return 1;
else
return (n * factorial(n-1));
}

 T(n) es el tiempo utilizado para una entrada n

1 si n=0
T(n) =
T(n-1) +1 en otro caso
Resolviendo la recurrencia
1 si n=0
T(n) =
T(n-1) +1 en otro caso

 T(n) = (T(n-2) +1) +1 = T(n-2) +2


= (T(n-3) +1) +2 = T(n-3) +3
= (T(n-4) +1) +3 = T(n-4) +4
...
generalizando :
= T(n-k) +k
Si k=n : = T(n-n) +n
= 1+n = max(0(1),O(n))
= O(n)
Otro ejemplo
public void MoveTower (int n, char src, char dst, char tmp) {
if (n > 0) {
MoveTower (n-1, src, tmp, dst);
MoveDisk (n, src, dst);
MoveTower (n-1, tmp, dst, src);
}
}

 Configurar la recurrencia T(n):

1 si n=0
T(n) =
2T(n-1) +1 en otro caso
Resolviendo la recurrencia
1 si n=0
T(n) =
1 + 2T(n-1) en otro caso

 Repetir la substitución
T(n) = 1 + 2T(n-1)
= 1 + [ 2 + 2T(n-2) ]
= 1 + [ 2 + ( 4 + 8T(n-3))]
...
Generalizar el patrón :
= 2i-1 + 2i T(n-i)

Resolver para n-i = 0 (i=n)


= 2n-1 + 2n T(0)
= 2n+1 -1
= 2n+1 ==> O(2n)

Вам также может понравиться