







Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Prepara tus exámenes
Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Prepara tus exámenes con los documentos que comparten otros estudiantes como tú en Docsity
Encuentra los documentos específicos para los exámenes de tu universidad
Estudia con lecciones y exámenes resueltos basados en los programas académicos de las mejores universidades
Responde a preguntas de exámenes reales y pon a prueba tu preparación
Consigue puntos base para descargar
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Comunidad
Pide ayuda a la comunidad y resuelve tus dudas de estudio
Ebooks gratuitos
Descarga nuestras guías gratuitas sobre técnicas de estudio, métodos para controlar la ansiedad y consejos para la tesis preparadas por los tutores de Docsity
Asignatura: Estructura de los computadores, Profesor: , Carrera: Ingeniería de Software, Universidad: UCM
Tipo: Apuntes
1 / 13
Esta página no es visible en la vista previa
¡No te pierdas las partes importantes!








No puede haber orden cuando hay mucha prisa Seneca
Resumen: En este tema se muestra la importancia de contar con algoritmos eficien- tes, se define qué se entiende por coste de un algoritmo y se enseña a comparar las funciones de coste de distintos algoritmos con el fin de decidir cuál de ellos es preferi- ble. Se define una jerarquía de órdenes de complejidad que ilustra la separación entre algoritmos eficientes y los que no lo son.
? Aproximadamente cada año y medio se duplica el número de instrucciones por se- gundo que son capaces de ejecutar los computadores. Ello puede inducir a pensar que basta con esperar algunos años para que problemas que hoy necesitan muchas horas de cálculo puedan resolverse en pocos segundos.
? Sin embargo hay algoritmos tan ineficientes que ningún avance en la velocidad de las máquinas podrá conseguir para ellos tiempos aceptables. El factor predominante que delimita lo que es soluble en un tiempo razonable de lo que no lo es, es precisamente el algoritmo elegido para resolver el problema.
? En este capítulo enseñaremos a medir la eficiencia de los algoritmos y a comparar la eficiencia de distintos algoritmos para un mismo problema. Después de la correc- ción, conseguir eficiencia debe ser el principal objetivo del programador. Mediremos principalmente la eficiencia en tiempo de ejecución, pero los mismos conceptos son aplicables a la medición de la eficiencia en espacio, es decir a medir la memoria que necesita el algoritmo.
? El siguiente programa ordena un vector a[0..n − 1] por el método de selección:
(^1) Ricardo Peña es el autor principal de este tema.
2 Capítulo 1. Análisis de la eficiencia
1 int a[n]; 2 int i, j, pmin, temp; 3 for (i = 0; i < n-1; i++) 4 // pmin c a l c u l a l a p o s i c i ó n d e l mínimo de a [ i.. n −1] 5 {pmin = i; 6 for (j = i+1; j < n; j++) 7 if (a[j] < a[pmin]) pmin = j; 8 // ponemos e l mínimo en a [ i ] 9 temp = a[i]; a[i] = a[pmin]; a[pmin] = temp; 10 }
? Una manera de medir la eficiencia en tiempo de este programa es contar cuántas instrucciones de cada tipo se ejecutan, multiplicar este número por el tiempo que emplea la instrucción en ejecutarse, y realizar la suma para los diferentes tipos. Sean
ta = tiempo de una asignación entre enteros (1.1) tc = tiempo de una comparación entre enteros ti = tiempo de incrementar un entero tv = tiempo de acceso a un elemento de un vector
La línea (3) da lugar a una asignación, a n− 1 incrementos y a n comparaciones, es decir, a un tiempo ta + (n − 1)ti + ntc. La línea (5) da lugar a un tiempo (n − 1)ta. El bucle interior for se ejecuta n − 1 veces, cada una con un valor diferente de i. Para cada valor de i y siguiendo el cálculo hecho para la (3), la línea (6) da lugar a un tiempo ta + (n − i − 1)ti + (n − i)tc. La línea (7) da, para cada valor de i, un tiempo mínimo de (n − i − 1)(2tv + tc), suponiendo que la instrucción pmin = j nunca se ejecuta. A ello hay que sumar (n − i − 1)ta en el caso más desfavorable en que dicha rama se ejecute todas las veces. El caso promedio tendrá un tiempo de ejecución entre estos dos. Finalmente, la línea (9) dará lugar a un tiempo (n − 1)(4tv + 3ta). Por tanto, el tiempo del bucle interior for, en el caso más desfavorable, se calcula mediante el siguiente sumatorio: n∑− 2
i=
(ta + tc + (n − i − 1)(ti + 2tv + ta + 2tc)) = P (n − 1) +
Qn(n − 1)
siendo P = ta + tc y Q = ti + 2tv + ta + 2tc.
Para no cansar al lector con tediosos cálculos, concluiremos que la suma de todos estos tiempos da lugar a dos polinomios de la forma:
Tmin = An^2 − Bn + C Tmax = A′n^2 − B′n + C′
donde A, A′, B, B′, C y C′^ son expresiones racionales positivas que dependen lineal- mente de los tiempos elementales descritos en 1.1.
? En este sencillo ejemplo se observan claramente los tres factores de los que en general depende el tiempo de ejecución de un algoritmo:
Estructura de Datos y Algoritmos
4 Capítulo 1. Análisis de la eficiencia
? Sea N el conjunto de los números naturales y R+^ el conjunto de los reales estricta- mente positivos.
Definición 1.1 Sea f : N −→ R+^ ∪ { 0 }. El conjunto de las funciones del orden de f (n), denotado O(f (n)), se define como:
O(f (n)) = {g : N −→ R+^ ∪ { 0 } | ∃c ∈ R+, n 0 ∈ N. ∀n ≥ n 0. g(n) ≤ cf (n)}
Asímismo, diremos que una función g es del orden de f (n) cuando g ∈ O(f (n)). También diremos que g está en O(f (n)).
n
? N R+
f : N ! R+^ [ { 0 } f (n) O(f (n))
O(f (n)) = {g : N ! R+^ [ { 0 } | 9 c 2 R+, n 0 2 N. 8 n n 0. g(n) cf (n)}
g f (n) g 2 O(f (n)) g O(f (n))
cf (n) g(n)
?
n O(f (n)) n 0
? g(n)
f (n) g^0 (n)
f (n) O(f (n))
? O(f (n)) f (n)
O(n) O(n^2 ) O(1) O(f (n)) f (n)
?
O(n^2 ) O(n log n)
?
120 n^2 2 n^2 O(n^2 )
? O(f (n)) (n+1)^2 2 O(n^2 )
? Generalizando, admitiremos también que una función negativa o indefinida para un número finito de valores de n pertenece al conjunto O(f (n)) si eligiendo n 0 suficien- temente grande, satisface la definición.
? Esta garantiza que, si el tiempo de ejecución g(n) de una implementación concreta de un algoritmo es del orden de f (n), entonces el tiempo g′(n) de cualquier otra implementación del mismo que difiera de la anterior en el lenguaje, el compilador, o/y la máquina empleada, también será del orden de f (n). Por tanto, el coste O(f (n)) expresa la eficiencia del algoritmo per se, no el de una implementación concreta del mismo.
? Las clases O(f (n)) para diferentes funciones f (n) se denominan clases de comple- jidad, u órdenes de complejidad. Algunos órdenes tienen nombre propio. Así, al orden de complejidad O(n) se le llama lineal, al orden O(n^2 ), cuadrático, el orden O(1) describe la clase de las funciones constantes, etc. Eligiremos como represen- tante del orden O(f (n)) la función f (n) más sencilla posible dentro del mismo.
? Nótese que la definición 1.1 se puede aplicar tanto a un análisis en el caso peor, como a un análisis en el caso promedio. Por ejemplo, hay algoritmos cuyo coste en tiempo está en O(n^2 ) en el caso peor y en O(n log n) en el caso promedio.
? Nótese también que las unidades en que se mide el coste en tiempo (horas, segundos, milisegundos, etc.), o en memoria (octetos, palabras, celdas de longitud fija, etc.) no son relevantes en la complejidad asintótica: dos unidades distintas se diferencian en una constante multiplicativa (e.g. 120 n^2 segundos son 2 n^2 minutos, ambos en O(n^2 )).
Estructura de Datos y Algoritmos
? Aplicando directamente la definición de O(f (n)), demostremos que (n+1)^2 ∈ O(n^2 ). Un modo de hacerlo es por inducción sobre n. Elegimos n 0 = 1 y c = 4, es decir demostraremos ∀n ≥ 1. (n + 1)^2 ≤ 4 n^2 : Caso base: n = 1, (1 + 1)^2 ≤ 4 · 12
Paso inductivo: h.i. (n + 1)^2 ≤ 4 n^2. Demostrémoslo para n + 1:
(n + 1 + 1)^2 ≤ 4(n + 1)^2 (n + 1)^2 + 1 + 2(n + 1) ≤ 4 n^2 + 4 + 8n (n + 1)^2 ≤ 4 n^2 + 6︸ ︷︷ ︸n + 1 ≥ 0
? También podemos probar que 3 n^6 ∈ O(2n). Si perteneciera, existiría c ∈ R+, n 0 ∈ N tales que 3 n^ ≤ c · 2 n^ para todo n ≥ n 0. Esto implicaría que ( 32 )n^ ≤ c para todo n ≥ n 0. Pero esto es falso porque dado un c cualquiera, bastaría tomar n > log 1 , 5 c para que ( 32 )n^ > c, es decir ( 32 )n^ no se puede acotar superiormente.
? La notación O(f (n)) nos da una cota superior al tiempo de ejecución t(n) de un algoritmo. Normalmente estaremos interesados en la menor función f (n) tal que t(n) ∈ O(f (n)). Una forma de realizar un análisis más completo es encontrar además la mayor función g(n) que sea una cota inferior de t(n). Para ello introducimos la siguiente medida.
Definición 1.2 Sea f : N −→ R+^ ∪ { 0 }. El conjunto Ω(f (n)), leído omega de f (n), se define como:
Ω(f (n)) = {g : N −→ R+^ ∪ { 0 } | ∃c ∈ R+, n 0 ∈ N. ∀n ≥ n 0. g(n) ≥ cf (n)}