Documentos de Académico
Documentos de Profesional
Documentos de Cultura
2019
• Eficiencia
Eligiendo un algoritmo
Problema: ordenamiento
Dados algoritmos de ordenamiento:
• SelectionSort
• Mergesort ¿Cuál elegir?
Eligiendo un algoritmo
Dado un problema, pueden existir distintos algoritmos que lo resuelven
• Eficiencia El segundo es más largo y un poco más difícil de entender que el primero.
Sin embargo, el segundo es mucho más eficiente el segundo.
Algoritmo
Datos de entrada
Computadora
Empírico
o Supone tener el código y ejecutarlo
o Se realiza ejecutando el programa sobre una colección de entradas.
o La medición depende de la computadora, SO, y del compilador
o El tiempo se mide en unidades de tiempo
Midiendo el tiempo de ejecución de un programa
Dos tipos de análisis:
Empírico
Teórico
o No se necesita el código
o Permite un análisis predictivo de la eficiencia
o No depende de las características de implementación
o ¿Cómo se mide el tiempo? Cantidad de trabajo realizado:
o cantidad de sentencias ejecutadas
o cantidad de operaciones relevantes que requiere la ejecución
Midiendo el tiempo de ejecución de un programa
Análisis teórico
Análisis depende del “tamaño de la entrada” del problema
Análisis teórico
Análisis depende del “tamaño de la entrada” del problema
Análisis teórico
Análisis teórico
• peor caso
• mejor caso
• caso promedio
Midiendo el tiempo de ejecución - Ejemplo
Problema: ¿existe un número entero x en un arreglo de n enteros?
Tamaño del problema = n (cantidad de elementos en el arreglo)
Algoritmo: búsqueda secuencial
Análisis del tiempo: supongamos que medimos la cantidad de comparaciones
necesarias (#C) para encontrar el elemento x :
mejor caso: x está en la primer posición del arreglo. #C = 1
peor caso: x no está en el arreglo. #C = n
caso promedio: asumiendo que x está en el arreglo y tiene
la misma probabilidad de que esté en una posición u otra. #C = ½ n
Midiendo el tiempo de ejecución - Ejemplo
Estimar el tiempo de ejecución de la siguiente función en el peor caso:
Fragmento:
Fragmento:
2 (n - i - 1 ) u
1 (n - i - 1 ) u
(peor caso) 1 (n - i - 1 ) u
1° Analicemos el bucle for
• For itera n - i - 1 veces
• Se ejecutan 4 sentencias elementales cada vez => 4 (n - i - 1 ) unidades
Midiendo el tiempo de ejecución - Ejemplo
Estimar el tiempo de ejecución de un fragmento del algoritmo de
ordenamiento selectionSort
Fragmento: 1u
2 (n - i - 1 ) u + 2u
1 (n - i - 1 ) u
1 (n - i - 1 ) u
1° Analicemos el bucle for
• For itera n - i - 1 veces
• Se ejecutan 4 sentencias elementales cada vez => 4 (n - i - 1 ) unidades
Fragmento: 1u
2 (n - i - 1 ) u + 2u
1 (n - i - 1 ) u
1 (n - i - 1 ) u
¿Operaciones elementales?
¿Tamaño de la entrada?
Analizando Algoritmos
• Alg 1: inserción
8n2 operaciones elementales
• Alg 2: mergesort
4 n log n operaciones elementales
1. Establecer un par testigo (c, n0) o una 3-upla (c1, c2, n0) (notación Θ).
2. Por manipulación algebraica demostrar que para el par o 3-upla y n ≥ n0 se cumple:
f(n) ≤ c g(n) // para O
f(n) ≥ c g(n) // para Ω
0 ≤ c1 g(n) ≤ f(n) ≤ c2 g(n) // para Θ
Recordar: • n0 N+ y c1 y c2 R+.
• Todas las pruebas son esencialmente las mismas, solo la manipulación algebraica varía.
¿Cómo probar que f(n) O(g(n))?
Dadas : f(n) =25 + 5 n2 y g(n) = n2 , ¿ f(n) O(g(n)) ? // demostrar si n2 es cota superior de f
para n=1 → 25 + 5 12 ≤ 30 12 30 ≤ 30
n=2 → 25 + 5 22 ≤ 30 22 45 ≤ 120
n=3 → 25 + 5 32 ≤ 30 32 70 ≤ 270
…
Para n0= 1 y c= 30 , n ≥ n0 se cumple que 25 + 5 n2 ≤ 30 n2, 25 + 5 n2 O(n2)
¿Cómo probar que f(n) O(g(n))?
O(g(n)) = { f(n): constantes positivas c y n0 : 0 ≤ f(n) ≤ c g(n) n ≥ no }
f(n) O(g(n)) n0 25 + 5 n2
¿Cómo probar que f(n) O(g(n))?
Para el mismo par de funciones ¿ podríamos haber hallado otro par testigo?
Dadas f(n) =25 + 5 n2 y g(n) = n2 , ¿ f(n) O(g(n)) ?
1. encontrar (n0, c) : 25 + 5 n2 ≤ c n2
Existen otras elecciones de constantes, pero lo importante es que “alguna elección exista”
¿Cómo probar que f(n) O(g(n))?
O(g(n)) = { f(n): constantes positivas c y n0 : 0 ≤ f(n) ≤ c g(n) n ≥ no }
y g(n) = n2 , 6 n2
c
par testigo
n0= 5 y c= 6
f(n) O(g(n)) 25 + 5 n2
n0
¿Cómo probar que f(n) O(g(n))?
O(g(n)) = { f(n): constantes positivas c y n0 : 0 ≤ f(n) ≤ c g(n) n ≥ no }
Dadas : f(n) = 25 + 5 n2
y g(n) = n2 , 12 n2
A partir de la gráfica,
deducir un par testigo
25 + 5 n2
n0 = ?
C=?
¿Cómo probar que f(n) O(g(n))?
O(g(n)) = { f(n): constantes positivas c y n0 : 0 ≤ f(n) ≤ c g(n) n ≥ no }
Dada f(n) = an2 + bn +c podemos decir que f(n) O(n2) -- a,b y c constantes
Demostración:
a + b/n +c/n2 ≤ a + b + c ≤ c0
𝑘
p (n) = 𝑖=0 𝑎𝑖 𝑛𝑖 , donde las 𝑎𝑖 son constantes y 𝑎𝑛 > 0
p (n) O ( nk )
Ejercicio: Demostrar
¿Cómo probar que f(n) O(g(n))?
Probamos que f(n) O(g(n)) partiendo de la definición y encontrando un par testigo
¿Cómo probar que f(n) O(g(n))? Partimos de la definición formal de Big-Oh,
asumir que el par testigo (n0 , c) existe, y derivar una contradicción.
n0 = 12, c = ¼ ¼ n2
n0
f(n) (g(n))
¿Cómo probar que f(n) (g(n))? Ejercicio
Ω (g(n)) = { f(n): constantes positivas c y n0 : 0 ≤ c g(n) ≤ f(n) n ≥ no }
Dada f(n) = an2 + bn +c podemos decir que f(n) Ω(n2) -- a,b y c constantes
Demostrar
¿Cómo probar que f(n) Î (g(n))?
Θ (g(n)) = { f(n): constantes positivas c1, c2 y n0: 0 ≤ c1 g(n) ≤ f(n) ≤ c2 g(n) n ≥ n0 }
c2
buscar un (n0, c1, c2 ) : n ≥ n0
c1 n2 ≤ ½ n2 – 3n ≤ c2 n2 ½ n2 ¼ n2
Dividimos por n2 c1
c1 ≤ ½ – 3/n ≤ c2
g es cota inferior
n0 = 12, c1 = ¼ , c2 = ½ n0= 12
f(n) (g(n))
¿Cómo probar que f(n) (g(n))?
Θ (g(n)) = { f(n): constantes positivas c1, c2 y n0: 0 ≤ c1 g(n) ≤ f(n) ≤ c2 g(n) n ≥ n0 }
n ≤ c2/6
Lo cual no es posible para un n arbitrariamente grande, ya que c2 es constante.
f(n) (g(n))
Ejercicios
1. Para cada par de funciones:
1.1. f(n) = 10 n + 15 y g(n) = n
1.2. f(n) = ½ n2 +1000 y g(n) = n3
15n +10
De valores a la tripla
(c1,c2 y n0) tal que
se cumpla que 15 g (n)
f(n) (g(n))
Describiendo el tiempo de ejecución de un programa
Sea T(n) el tiempo de ejecución de un programa en el “peor de los casos”
para una entrada de tamaño n.
T(n) O(g(n))
simplicidad:
• g(n) es un término simple
• el coeficiente del término es 1
Por otro lado, como una expresión de tiempo de ejecución, nos gustaría decir
T(n) (0.5 n2) porque es "más estricto”.
Pero…. El coeficiente del término es 1, no nos interesa el valor exacto sino la
forma de la función
Aritmética en notación O
Regla para la suma:
A TA(n)
Programa P TP (n) = TA(n) + TB(n)
TB(n)
B
if (<condición>) → O (f(n))
<Sentencia S1> → O (g(n))
else
<Sentencia S2> → O (h(n))
Tif (n) ≤ t cond + c max (TS1, TS2) //solo se ejecuta una rama
aux= x; T( 𝒏 ) ϵ O ( 𝟏 )
x= y;
y= aux;
}
Analizando el tiempo de ejecución de un programa: Ejemplos
int i= 1; T(n) c0 + n
c1 + c2 + c3 + c1
i=1
while (i <= n) { c = c1 + c2 + c3
i++; } T( 𝒏 ) ϵ O ( 𝒏 )
}
Analizando el tiempo de ejecución de un programa: Ejemplos
menor= 0;
T(𝑛) c0 + c1 + 𝑛−1
𝑖=1 𝑐2 + 𝑐3 + 𝑐4
for (int j= 1; j < n; j++)
𝑐 = 𝑐2 + 𝑐3 + 𝑐4
if (A[j] < A[menor]) c0 + c1 + c (n – 1)
ϵ O (𝟏)
menor = j; c0 + c1 + c n – c
... T( 𝒏 ) ϵ O ( 𝒏 )
Analizando el tiempo de ejecución de un programa: Ejemplos
O(1) constante
O(log n) logarítmico
O(2n)
O(n) lineal
polinomial O(n!) exponencial
O(n log n) n log n
O(nn)
O(n2) cuadrático
O(n3) cúbico
Tiempo de ejecución como función del tamaño de la entrada
El tiempo de ejecución “crece” como una función del tamaño de las entradas
David Harel (2012)
Ritmo de crecimiento de algunas funciones
Bibliografía