Las matemáticas como medio para medir la eficiencia de los Algoritmos Computacionales ¿Qué es un algoritmo?  “(del árabe al-Khowârizmî, sobrenombre del célebre matemático árabe.

Download Report

Transcript Las matemáticas como medio para medir la eficiencia de los Algoritmos Computacionales ¿Qué es un algoritmo?  “(del árabe al-Khowârizmî, sobrenombre del célebre matemático árabe.

Las matemáticas como
medio para medir la
eficiencia de los Algoritmos
Computacionales
¿Qué es un algoritmo?
 “(del árabe al-Khowârizmî, sobrenombre
del célebre matemático árabe Mohámed
ben Musa). Conjunto ordenado y finito de
operaciones que permite encontrar la
solución a un problema…”
 Un algoritmo, puede expresarse en
términos de un lenguaje de programación,
para obtener un programa que resuelve el
problema por medio de la computadora.
Cita...
 “No hay un incremento concebible en el poder de las
computadoras que pueda saturar la demanda científica: aún
pensando que una computadora posea un ciclo de tiempo
subnuclear (10-23 seg.) y densidades de almacenamiento
subnucleares (1039 bits/cm3), ésta no podría manejar la
mayoría de los problemas que son importantes en la
investigación científica básica y aplicada. Por lo tanto, existirá
siempre una fuerte presión para incrementar la eficiencia de
los programas, para poder incrementar también la cantidad de
información últil generada por un programa.”
Ken Wilson, Nóbel de Física 1982
Áreas de estudio
 ¿Cómo construir algoritmos?
 Técnicas de diseño
 ¿Cómo expresar algoritmos?
 Enfoques de los lenguajes de programación
 ¿Cómo validar algoritmos?
 Verificación formal
 ¿Cómo analizar algoritmos?
 Complejidad computacional, eficiencia, legibilidad,
usabilidad, etc...
Análisis de algoritmos
 Si se tuvieran 2 programas que hacen lo
mismo, ¿cómo se podrían comparar?
1. Eficiencia:
 Tiempo de ejecución
 Uso de espacios de memoria
2. Facilidad de lectura, mantenimiento,
rapidez para codificarlo.
Medición del tiempo de
ejecución
 El tiempo de ejecución depende de:
1. La entrada al programa:
Su tamaño
Sus características
2. La calidad del código generado para el
programa por el compilador .
3. La rapidez de las instrucciones de
máquina.
4. La complejidad de tiempo del
algoritmo.
¿Cómo medir?
 Cantidad de instrucciones básicas (o
elementales) que se ejecutan.
 Ejemplos de instrucciones básicas:






asignación de escalares
lectura o escritura de escalares
saltos (goto’s) implícitos o explícitos.
evaluación de condiciones
llamada a funciones
etc.
Ejemplo
cont = 1;
while (cont <= n) do {
x = x + a[cont];
x = x + b[cont];
cont = cont + 1;
}
1
n+1
n
n
n
n (goto implícito)
1 goto en falso.
TOTAL: 5n + 3
Ejemplo
z = 0;
for (int x=1; x<=n; x++)
for (int y=1; y<=n; y++)
z = z + a[x,y];
1
1 asignación + (n+1) comparaciones
(n+2)*n = n2 +2n
n*n
= n2
2n2 (incremento + goto implícito)
n (goto en falso for y)
2n (incremento + goto implícito)
1 (goto en falso for x)
TOTAL: 4n2 + 6n + 4
Consecuencia…
 Se requiere contar con una notación que permita
comparar la eficiencia entre los algoritmos…
 La NOTACIÓN ASINTÓTICA es la propuesta de notación
aceptada por la comunidad científica para describir el
comportamiento en eficiencia (o complejidad) de un
algoritmo.
 Describe en forma sintética el comportamiento de la
función que con la variable de entrada, determina el
número de operaciones que realiza el algoritmo.
NOTACIÓN ASINTÓTICA
 COMPLEJIDAD TEMPORAL (y ESPACIAL).
Tiempo (o espacio) requerido por un algoritmo,
expresado en base a una función que depende
del tamaño del problema.
 COMPLEJIDAD TEMPORAL ASINTÓTICA (y
ESPACIAL). Comportamiento límite conforme el
tamaño del problema se incrementa. Determina
el tamaño del problema que puede ser resuelto
por un algoritmo.
Definición
 Se dice que la función f(n) “es de orden g(n)”
[O(g(n))], si existen constantes positivas c y n0
tales que f(n) <= c g(n) cuando n >= n0
 Ejemplos:
 n+5 es O(n) pues n+5 <= 2n para toda n >= 5
 (n+1)2 es O(n2) pues (n+1)2 <= 4n2 para n>= 1
 (n+1)2 NO es O(n) pues para cualquier c > 1
no se cumple que (n+1)2 <= c*n
Ordenes más comunes de los
algoritmos









O(1)
O(n)
O(n2 )
O(n3 )
O (nm )
O(log(n))
O(nlog(n))
O(mn )
O(n!)
Constante
Lineal
Cuadrático
Cúbico
Polinomial
Logarítmico
nlog (n)
exponencial
factorial
Comportamiento
de las funciones
n2
n sqrt(n
n log n
n
log n
Otro método para calcular el orden
de un problema
 Consiste en aplicar reglas a los estatutos
estructurados:
1.Secuencia de instrucciones
2.Decisiones (ejemplo: if)
3.Ciclos (ejemplo: while)
4.Recursividad
Regla 1: Secuencia de
instrucciones
O(g1(n))
O(g2(n))
≈ O( mayor(g1(n), g2(n), …, gm(n) )
O(g3(n))
Ejemplo:
 Una secuencia de 3 ciclos:
O(gm(n))
 Tendrá como orden total…
 Ciclo 1 = O(n)
 Ciclo 2 = O(log n)
 Ciclo 3 = O(n2)
 O(n2).
Regla 2: Decisiones
≈ O( mayor(g1(n), g2(n)) )
O(g1(n))
O(g2(n))
Ejemplo:
 Una decisión con:
 Rama then = O(n log n)
 Rama else = O(log n)
 Tendrá como orden total…
 O(n log n).
Regla 3: Ciclos
≈ O( m * g(n) )
O(g(n))
Se repite
m veces
Ejemplo:
 Un ciclo cuya instrucción:
 Tiene un O(log n)
 Se repite n/2 veces
 Tendrá como orden total…
 O(½ n log n) = O(n log n).
Consideraciones especiales
 En decisiones y ciclos anidados:
 Analizar el código desde la instrucción más
interna hacia el más externa.
 Tip para los ciclos:
 ¿“Normalmente” cuál es el orden de la
instrucción interna?
 Si la variable de control se incrementa o
decrementa con un valor constante: Orden
LINEAL.
 Si la variable de control se multiplica o divide por
un valor constante: Orden LOGARÍTIMICO.
Ejemplo: Sort por intercambio
for (int i=1; i<n; i++)
for (int j=i+1; j<=n;j++)
if (a[ j ] < a[ i ])
intercambia(a[ i ], a[ j ]); → O( 1 )
→ O( 1 )
Regla 2: Decisiones = mayor de las 2 ramas
Ejemplo: Sort por intercambio
Peor caso: se repite n-1 veces
for (int i=1; i<n; i++)
for (int j=i+1; j<=n;j++)
if (a[ j ] < a[ i ])
→ O( n )
→ O( 1 )
intercambia(a[ i ], a[ j ]);
Regla 3: Ciclos = # veces * orden de la instrucción interna
Ejemplo: Sort por intercambio
Se repite n-1 veces
for (int i=1; i<n; i++)
for (int j=i+1; j<=n;j++)
if (a[ j ] < a[ i ])
intercambia(a[ i ], a[ j ]);
→ O( n )
→ O( n2 )
Regla 3: Ciclos = # veces * orden de la instrucción interna
Ejemplo: Multiplicación de
matrices
a11 a12 … a1n
a21 a22 … a2n
…
… …
…
b11 b12 … b1m
X b21 b22 … b2m
…
am1 am2 … amn
c11 c12 … c1m
c21 c22 … c2m
…
… …
…
cm1 cm2 … cmm
… …
…
=
bn1 bn2 … bnm
c11 = a11*b11+a12 *b21 +…+ a1n *bn1
c12 = a11*b12+a12 *b22 +…+ a1n *bn2
…
c21 = a21*b11+a22 *b21 +…+ a2n *bn1
…
cmm = am1*b1m+am2 *b2m +…+ amn *bnm
cij =
n
 aikbkj
k=1
Ejemplo: Multiplicación de
matrices
O( n3 ) ← for i = 1 to n do
O( n2 ) ← for j = 1 to n do
O( 1 ) ← C[i,j] = 0;
O( n ) ← for k = 1 to n do
O( 1 ) ← C[i,j] = C[i,j] + A[i,k]*B[k,j];
Regla 4: Recursividad
 La complejidad de tiempo se obtiene contando la cantidad
de veces que se hace la llamada recursiva.
 Casos que “normalmente” se dan:
 Orden LINEAL si sólo se tiene una llamada recursiva,
con incrementos o decrementos en el parámetro de
control.
 Orden LOGARITMICO si sólo se tiene una llamada
recursiva, con multiplicaciones o divisiones en el
parámetro de control.
 Si hay más de una llamada recursiva, el orden puede
tender a ser EXPONENCIAL.
Ejemplo: Fibonacci (Iterativo)
ant = 1;
--> 1
act = 1;
--> 1
while (n>2){ --> n-2 + 1
aux = ant + act;
--> n-2
ant = act;
--> n-2
act = aux;
--> n-2
n = n - 1;
--> n-2
}
--> n-2+1
write (act);
--> 1
T(n) = 6n-7
Por lo tanto el orden
del algoritmo es
O(n)
Ejemplo: Fibonacci (recursivo)
Function fibonacci (n:int): int;
if (n < 3) return 1;
else return fibonacci(n-1) + fibonacci(n-2);
 ¿Cómo obtener la complejidad de tiempo
del algoritmo?
 Cantidad de llamadas recursivas: 2 en
cada llamada.
 Algoritmo de orden: O(2n/2)
Análisis de Fibonacci
(recursivo)
f(5)
f(3)
f(1)
f(4)
f(2)
f(2)
f(3)
f(1)
Relación:
El término T(n) requiere
T(n-1)+T(n-2)+1 términos
para calcularse.
f(2)
¿Cuántos términos
se requieren para
calcular:
f(5)? --> 9
f(4)? --> 5
f(3)? --> 3
-->
1
f(2)?
--> 15
f(6)?
Análisis de Fibonacci
 Si el término T(n) requiere T(n-1)+T(n



2)+1 términos para calcularse…
se puede decir que T(n) > 2 * T(n-2) …
y por lo tanto: T(n) > 2 * 2 * T(n-4) …
Por lo tanto:
y T(n) > 2 * 2 * 2 * T(n-6) …
T(n) > 2n/2
y así sucesivamente hasta:
y podemos decir
que el orden del
T(n) > 2 * 2 * 2 * …. * 2 * T(1)
algoritmo es
n/2 veces
O(2n/2)