34
Unidad II Tema 4: Análisis de Algoritmos Profesor: Jorge Escalona / Tobías Bolívar Email: [email protected] / [email protected] Página Web: http://estructuradatos.tripod.com

Tema4

Embed Size (px)

Citation preview

Unidad II

Tema 4: Análisis de Algoritmos

Profesor: Jorge Escalona / Tobías Bolívar

Email: [email protected] / [email protected]

Página Web: http://estructuradatos.tripod.com

Complejidad Computacional

• Complejidad Computacional

• Límites asintóticos

• Notación O

• Planteamiento de ecuaciones de recurrencia

• Solución de ecuaciones de recurrencias

Objetivos

• El alumno calculará la complejidad de un algoritmo: en el peor de los casos, en el promedio de los casos, y en el mejor de los casos, y determinará sus límites asintóticos.

• Dados dos algoritmos, el alumno determinará bajo que circunstancias uno es mejor que otro, basándose en los tiempos de corrida y la complejidad asintótica de ambos.

Medidas de Desempeño

• Cantidad de almacenamiento principal requerido por sus variables

• Cantidad de tráfico que genera en una red de computadoras

• Cantidad de información que debe moverse desde y hacia las unidades de almacenamiento secundario

• Simplicidad del algoritmo

• Tiempo de cómputo

Tiempo de Ejecución de un Algoritmo

A B C D E F G

ENTRADA

5 min

4 min

3 min

2 min

1 min

TIE

MP

O

Peor Caso

Mejor Caso

Caso Promedio?

Medición del Tiempo de Ejecución de un

Algoritmo

•Cómo podemos medir el tiempo

de ejecución de un algoritmo?

•Estudio Experimental:

• Escribir un programa que

implemente el algoritmo.

• Ejecutar el programa con un

conjunto de datos de tamaño y

composición variable.

• Usar algún método para obtener

una medida precisa del tiempo de

ejecución actual. Ejemplo Java: System.CurrenTimeMillis()

• El estudio experimental presenta algunos inconvenientes:

• Es necesario implementar y probar el algoritmo para

determinar su tiempo de ejecución.

• El experimento puede ser hecho sólo sobre un conjunto limitado de entradas, por lo que puede no ser indicativo sobre otros conjuntos de entradas no

contempladas en el experimento.

• Para poder comparar dos algoritmos, debe usarse el

mismo ambiente de hardware y software.

Medición del Tiempo de Ejecución de un

Algoritmo

• Como alternativa, se puede utilizar una metodología general para analizar el tiempo de ejecución de un

algoritmo que:

• Use una descripción de alto-nivel del algoritmo en vez

de una implementación.

• Tome en consideración todos los posibles conjuntos de entrada

• Permita evaluar la eficiencia de un algoritmo,

independientemente de la plataforma de hardare y software en el que se implemente.

Medición del Tiempo de Ejecución de un

Algoritmo

Medición del Tiempo de Ejecución de un

Algoritmo

• Operaciones primitivas: operaciones de bajo nivel que pueden ser comúnmente implementadas en la mayoría de

los lenguajes de programación y que pueden ser

identificadas en pseudo-código.

• Llamar a un procedimiento o función;

• Ejecutar una operación aritmética (ej. una suma);

• Comparar dos números, etc.

• Inspeccionando el pseudo-código se puede contar el

número de operaciones primitivas ejecutadas por un algoritmo.

Medición del Tiempo de Ejecución de un

Algoritmo

Ejemplo:

Algoritmo ArregloMaximo(A,n)

Entrada: un arreglo A guardando números enteros

Salida: el elemento máximo de A

Max ← A[0] (1 vez)

for i ← 1 to n - 1 do (n veces)

if Max < A[i] then (n-1 veces en peor caso)

Max ← A[i] (n-1 veces en peor caso)

return Max (1 vez)

Complejidad Temporal

Definición: el tiempo requerido (unidades de tiempo)

por un algoritmo para procesar una entrada de tamaño

n.

Sea T(n) el tiempo de corrida de algún programa,

debemos asumir:

1. El argumento n es un entero no negativo, y

2. T(n) es no negativo para todos los argumentos de n

Complejidad constante

Cuando la complejidad del algoritmo puede expresarse como

una función constante T(n)=a, se dice que es constante, no

depende de n.

Ejemplo 1: El procedimiento, eleva al cubo, recibe n y

regresa el cubo de n. T(n)=c1

1c1return n*n*n;

# de vecesCostoint eleva al cubo (int n)

Complejidad lineal

Cuando la complejidad de un algoritmo puede

expresarse como una función lineal

T(n)=an + b

donde a y b son constantes se dice que es

lineal en n.

Complejidad lineal

Ejemplo2: El siguiente procedimiento inicializa un arreglo de

n elementos.

6.

5.

nc44. i++

nc33. A[i]=1;

n+1c22. while (i<=n)

1c11. i=1;

# de veces Costovoid inicializa(int *A, int n)

Complejidad lineal

T(n) = c1 + (n+1)c2 + nc3 + nc4

= nc2 + nc3 + nc4 + c1 + c2

= (c2+c3+c4)n + (c1+c2)

= an + b

Si asignamos el valor de una unidad de tiempo para cada instrucción, la complejidad del procedimiento inicializa es T(n)=3n+2 y es lineal.

Complejidad cuadrática

Cuando la complejidad de un algoritmo puede

expresarse como una función cuadrática del tipo

T(n)=an2+bn+c

donde a, b y c son constantes, se dice que el

algoritmo es cuadrático en n.

Complejidad cuadrática

Ejemplo 3: Analicemos el siguiente código.

1. for(i=1; i<=n-1; i++)

2. for(j=1; j<=n-1; j++)

3. A[i,j]=1;

Ciclo Interno:

c1 + c2(n) + c3(n-1) + c4(n-1) = 1 + n + 2(n-1) =3n – 1

Ciclo Externo:

c1 + c2(n) + c3(n-1) + (3n - 1)(n-1) =

1 + 2n - 1 + 3n2 -3n - n + 1= 3n2 - 2n + 1

Casos de Complejidades

• Complejidad en el mejor de los casos: se define T(n) como el tiempo mínimo de corrida para todas las entradas de tamaño n.

• Complejidad en el peor de los casos: se define T(n) cómo el tiempo máximo de corrida para todas las entradas de tamaño n.

• Complejidad promedio: otra medida común de desempeño es Tavg(n), el tiempo promedio de corrida del programa sobre todas las entradas de tamaño n. Aún cuando el tiempo promedio es una medida más realista, en la práctica es más difícil de calcular que el peor de los casos.

El peor de los casos

• Es un límite superior del tiempo de corrida

• Frecuentemente ocurre

• Es más fácil de calcular que el promedio.

Notación Asintótica

Cuando observamos entradas de tamaño lo suficientemente grandes para que sólo el orden de crecimiento de la complejidad sea relevante, estamos estudiando la eficiencia asintótica de los algoritmos.

Casos de Complejidades

•Para especificar la cota superior de la razón de crecimiento de T(n) se

usa la notación O(f(n)).

Formalmente, decimos que T(n) es O(f(n)) si existe un entero n0 y una

constante c > 0 tal que para todos los enteros n ≥ n0, tenemos que

0

2000

4000

6000

0 1 10 50 100 500 1000

T(n)=3n+2

cf(n)

Notación O mayúscula

0 ≤ T(n) ≤ cf(n).

0

5000

10000

15000

20000

25000

30000

35000

1 2 5 10 50 100 500 1000

T(n)=3(n log n)

cf(n)=3logn

Notación Ω

• Para especificar la cota inferior de la razón de crecimiento de T(n)

se usa la notación Ω(f(n)).

• Formalmente, decimos que T(n) es ΩΩΩΩ(f(n)) si existe un entero n0 y una constante c > 0 tal que para todos los enteros n ≥ n0, tenemos que 0 ≤ cf(n) ≤ T(n).

•Ejemplo: 0 ≤ n2 ≤ 2n2 ≤ 3n2

0

500000

1000000

1500000

2000000

2500000

3000000

3500000

10 50 100 500 1000

T(n)=2n^2)

c1f(n)=n^2

c2f(n)=3n^2

Notación Θ

•Formalmente, decimos que T(n) es ΘΘΘΘ(f(n)) si existe un entero n0 y las constantes c1 y c2 > 0 tal que para todos los enteros n ≥n0, tenemos que:

0 ≤ c1f(n) ≤ T(n) ≤ c2f(n)

•Instrucciones secuenciales simples:s1; s2; …. ; sk•Complejidad es O(1)

•Ciclos simples:

for(i=0;i<n;i++) s;

donde s is O(1)

•Complejidad es n O(1) o O(n)

•Ciclos anidados:for(i=0;i<n;i++)

for(j=0;j<n;j++) s;

•Complejidad es n O(n) or O(n2)

Análisis de Complejidad de un Algoritmo

Análisis de Complejidad de un Algoritmo

•Ciclos con índice que no varían linealmenteh = 1;

while ( h <= n )

s;

h = 2 * h;

•h toma valores 1, 2, 4, … hasta que excede a n

• Hay 1 + log2n iteraciones

• Complejidad es O(log n)

Análisis de Complejidad de un Algoritmo

•Ciclos con índices que dependen de otro índice de un

ciclo externo:

for(j=0;j<n;j++)

for(k=0;k<j;k++)

s;

•Ciclo interno se ejecuta

1, 2, 3, …., n veces

•Complejidad es O(n2)

Se debe distinguir este casodonde el contador de la iteraciónse incrementa (o decrementa)

por una constante O(nk)del caso previo donde el índice

cambia por un factor O(log

n)

ΣΣΣΣ i =i=1

n(n+1)

2

Principios generales para la notación O

1. Factores constantes no importan. Para cualquier constante positiva d y cualquier función T(n),

T(n) es O(dT(n)).

2. Términos de orden menor, no importan. Suponga que T(n) es una función polinomial de forma:

aknk + ak-1n

k-1 +...+ a2n2 + a1n + a0

donde akn es positivo. Entonces podemos concluir que T(n) es O(nk)

La regla de la suma

• Suponga que un programa consiste de dos partes, una de

las cuales es de complejidad O(n2) y la otra de O(n3). En

muchos casos como este, es posible sumar estas dos

complejidades usando la regla de la suma:

• Suponga que T1(n) es de O(f1(n)), mientras que T2(n) es de

O(f2(n)), además suponga que f2 no crece tan rápido como

f1; esto es f2 es de O(f1). Entonces podemos concluir que

T1(n) + T2(n) es O(f1(n)).

La regla de la suma

1. readln(n);

2. for i:=1 to n do

3. for j:=1 to n do

4. A[i,j]:=0;

5. for i:=1 to n do

6. A[i,i]:=1;

T1(n)=1 es =O(1), T2(n)=O(n2), T3(n)=O(n)

T1(n)+T2(n)+T3(n) es de O(n2)

La regla de la suma

0

20

40

60

80

1 2 3 4 5 6 7 8

T1(n)

T2(n)

T3(n)

Complejidades comunes

Notación O Nombre

O(1) Constante

O(log n) Logarítmico

O(n) Lineal

O(n log n) n log n

O(n2) Cuadrático

O(n3) Cúbico

O(2n) Exponencial

Comparación de algoritmos

• Suponga que para algún problema tenemos la opción de utilizar un programa lineal A cuyo tiempo de corrida es TA(n)=100n (milisegundos requeridos) o un programa cuadrático B cuyo tiempo de corrida es TB(n)=2n2.

• Si TA(n)=100n, en un segundo 1000=100n puedo procesar una entrada de tamaño n=10, mientras que con TB(n)=2n2 una de tamaño 1000=2n2

proceso n=(500)1/2 ≈ 22.3 = 22 elementos

Comparación de algoritmos

0

5000

10000

15000

20000

0 20 40 60 80 100

TA

TB

Comparación de algoritmos

Tiempo

(segundos)

Máximo tamaño del

problema que se puede

resolver con A

Máximo tamaño del

problema que se puede

resolver con B

1 10 22

10 100 70

100 1000 223

1000 10000 707

1) Cuál algoritmo es más eficiente para un problema de tamaño 30?

2) Cuál algoritmo es más eficiente para un problema de tamaño 80?

3) Cuál algoritmo es más eficiente para un problema de tamaño 100 000?

4) A partir de qué valor el algoritmo A es más eficiente que el algoritmo B?

Tema 4: Autoevaluación

x:= 0

s := n*n

for i := 1 to n

for j := s downto 1 do

x := x +2

1. Analizar el Tiempo de Ejecución T(n) y la complejidad O(n), de los siguientes fragmentos de

código:

a) for i := 1 to n do

x = x * x

for i := 1 to x do

y := y * x

b)

x := 1while i <= n do

j = n;while j > i do

x := x * xj := j div 4

endi := i + 2

end

c)while i < n

s = f(i)

i = i * 2

end

Nota: T(f(i)) = O(n2)

d)

2. Un algoritmo A resulve un problema de tamaño n en tiempo en n minutos. Otro algoritmo

B resuelve el mismo problema de tamaño n en n3 milisegundos. Haga una tabla

comparativa de los tiempos de ejecución de estos algoritmos para problemas de tamaño

10, 100, 1000, 10000, 100000, 1000000....Cuál de los dos es mejor? Bajo que

circunstancias seleccionará al algoritmo A o al algoritmo B?