January 15, 010
1 Pseudocódigo 3
Modelos de referencia Antes de analizar un algoritmo debemos tener un modelo de la implementación de la tecnología que se va a usar, incluyendo un modelo para los recursos de esa tecnología y sus costos. Nosotros... Asumamos un modelo de computación genérico de acceso aleatorio (Random-Access Machine) y nuestros algoritmos son implementados como programas de computadoras
El modelo RAM Las instrucciones se ejecutan una tras otra No hay operaciones concurrentes
El modelo RAM Las instrucciones se ejecutan una tras otra No hay operaciones concurrentes Contiene instrucciones comúnmente encontradas en computadores reales: aritméticas( +, -, *, /, %), movimiento de data (cargar, copiar, almacenar) y control (condicionales, llamado de funciones y retorno)
El modelo RAM Las instrucciones se ejecutan una tras otra No hay operaciones concurrentes Contiene instrucciones comúnmente encontradas en computadores reales: aritméticas( +, -, *, /, %), movimiento de data (cargar, copiar, almacenar) y control (condicionales, llamado de funciones y retorno) No modela la jerarquía de memoria que se encuentra en las arquitecturas modernas: cache, memoria virtual, etc...
El modelo RAM Las instrucciones se ejecutan una tras otra No hay operaciones concurrentes Contiene instrucciones comúnmente encontradas en computadores reales: aritméticas( +, -, *, /, %), movimiento de data (cargar, copiar, almacenar) y control (condicionales, llamado de funciones y retorno) No modela la jerarquía de memoria que se encuentra en las arquitecturas modernas: cache, memoria virtual, etc...
Pseudocódigo El tiempo que toma Insertion Sort depende fundamentalmente de la entrada: el ordenamiento de 1,000 números toma más que el de 10. Más aun, el Insertion Sort puede tomar distinta cantidad de tiempo para ordenar dos entradas del mismo tamaño pero diferiendo en qué tan ya ordenadas estén. Preliminares... El tiempo de ejecución de un algoritmo en función de su entrada es la cantidad pasos ejecutados. Asumeremos que un tiempo constante se necesita para ejecutar cada ĺınea de código. Las ĺıneas pueden tener distintos tiempos, pero asumeremos que el tiempo de la i-ésima ĺınea toma Ci, donde Ci es constante.
Pseudocódigo Outline Pseudocódigo Las ĺıneas donde están definidos los bucles se ejecutan una vez más que el cuerpo del bucle mismo. Por qué? El tiempo de ejecución del algoritmo es la suma de los tiempos de ejecución de cada sentencia ejecutada. Una sentencia que tome Cx tiempo y se repita n veces contribuye ncx al tiempo de ejecución del algoritmo.
Pseudocódigo Tiempo de ejecución del Insertion Sort Sumando los productos anteriores (costo x veces) llegamos a la siguiente fórmula: T(n) = c 1 n + c (n 1) + c 4 (n 1) + c 5 n j= t j + c 6 n j= (t j 1) + c 7 n j= (t j 1) + c 8 (n 1)
Pseudocódigo Tiempo de ejecución del Insertion Sort () Notando que: n j= t j = n(n+1) 1 y n j= (t j 1) = n(n+1) Entonces: T(n) = c 1 n +c (n 1)+c 4 (n 1)+c 5 ( n(n+1) 1)+c 6 ( n(n+1)) +c 7 ( n(n+1) ) T(n) T(n) = ( c 5 + c 6 + c 7 )n +(c 1 +c +c 4 + c 5 c 6 c 7 +c 8 )n (c +c 4 +c 5 +c 8 )
Pseudocódigo Este tiempo de ejecución puede ser expresado de la forma an + bn + c para las constantes a, b y c que dependen de los costos c i. Por lo tanto, es una función cuadrática Generalmente nos interesamos por el peor tiempo de ejecución de los algoritmos, porque... (1) Es un ĺımite superior, garantiza que el algoritmo no excederá tal ĺımite () El peor de los casos ocurre frecuentemente. Considera el ejemplo de una búsqueda en una base de datos. (3) El caso promedio es difícil de especificar y termina siendo una función similar a la del peor de los casos
En el análisis de algoritmos nos interesa la proporción o orden de crecimiento. Este orden de crecimiento es el término de mayor orden del polinomio que expresa el tiempo de ejecución (n en el caso del ordenamiento por inserción Esto es porque, a medida que n crece, los otros términos no aportan tanto. En el caso del ordenamiento por inserción, decimos entonces que su tiempo de ejecución en el peor de los casos es de orden θ(n ) Hay distintas notaciones para expresar el tiempo de ejecución...
Notación Theta Dada una función g(n), decimos por Θ(g(n)) el conjunto de funciones Θ(g(n)) = {f(n): existen constantes positivas c 1, c yn 0 tal que 0 <= c 1 g(n) <= f (n) <= c g(n) para todas las n => n0} O sea Una función f(n) pertenece al conjunto Θ(g(n)) si existen constante c 1 yc tal que pueda estar en el medio entre c 1 g(n)yc g(n), para una n suficientemente grande. Al decir f(n) = Θ(g(n)) se debe leer f(n) es del orden Θ(g(n))
Notación Big Oh Dada una función g(n), denotamos por O(g(n)) el conjunto de funciones O(g(n)) = {f(n): existen constantes positivas cyn 0 tal que f (n) <= cg(n) para todas las n => n0} O sea La notación O sólo denota un ĺımite superior. Es como decir, a lo sumo X. Por lo tanto, n = O(n ). Esto implica también que al utilizar la notación O para expresar el peor tiempo de ejecución de un algoritmo, también estamos expresando tiempo de ejecución para cada entrada. Al decir f(n) = O(g(n)) se debe leer f(n) es del orden O(g(n))
Notación Omega Dada una función g(n), denotamos por Ω(g(n)) el conjunto de funciones Ω(g(n)) = {f(n): existen constantes positivas cyn 0 tal que 0 <= cg(n) <= f (n) para todas las n => n0} O sea Así como O(g(n)) expresa un ĺımite asintótico superior, Ω(g(n)) exprea un ĺımite asintótico inferior. Esto implica, similar a Big Oh, que al expresar el mejor tiempo de ejecución con Ω también estamos expresando el tiempo de ejecución de todas las entradas. Ejemplo: El tiempo de ejecución del insertion-sort cae entre Ω(n)yO(n ). Al decir f(n) = Ω(g(n)) se debe leer f(n) es del orden Ω(g(n))
Small o Outline Dada una función g(n), denotamos por o(g(n)) el conjunto de funciones o(g(n)) = {f(n): existen constantes positivas cyn 0 tal que 0 <= f (n) < cg(n) para todas las n => n0} O sea Small o representa, a diferencia de Big O, un ĺımite asintótico superior pero no fuerte. Ejemplo: n = o(n ) pero no n = o(n ) Al decir f(n) = o(g(n)) se debe leer f(n) es del orden o(g(n))