Cap´ıtulo 1: Introducci´
on
Del libro: Dise˜no de Algoritmos
C y Pascal
Agosto - 2011
´Indice
1 Algoritmos, Estructura de Datos y Programas
Algoritmos
Estructura de Datos Programas
2 Tipos de Datos y Tipos Abstractos de Datos
Tipos de Datos
Tipos abstractos de datos
3 Medida de tiempo de ejecuci´on de un programa
Comportamiento Asint´otico de Funciones Clases de comportamiento Asint´otico
Algoritmos
Definici´on:
Es una secuencia de acciones, cuya ejecuci´on conduce a la obtenci´on de una soluci´on para un problema determinado. Seg´un Dijkstra, un algoritmo corresponde a la descripci´on de un patr´on de comportamiento, expresado en un conjunto finito de acciones.
• Los algoritmos son parte del d´ıa a d´ıa de las personas. Ejemplos de algoritmos:
• Instrucciones para el uso de medicamentos.
• Instrucciones para armar un aparato electr´onico.
• Una receta de cocina.
• Si realizamos la operaci´on a + b podemos percibir un patr´on de
Estructura de Datos
• Las estructuras de datos y algoritmos est´an estrechamente relacionados: • No se puede estudiar las estructuras de datos, sin considerar los algoritmos
asociados a ellos.
• La elecci´on de un algoritmo, depende en general, de la representaci´on y la estructura de datos.
• Para resolver un problema es necesario escoger una abstracci´on de la realidad, en general, mediante la definici´on de un conjunto de datos que representa la situaci´on real.
Selecci´
on de la representaci´
on de los datos
• La elecci´on de la representaci´on de los datos es determinada, entre otras, por las operaciones a ser realizadas sobre los datos.
• Si consideramos una operaci´on de adici´on:
• Para n´umeros peque˜nos, una buena representaci´on es por medio de barras verticales (|).
• La representaci´on por d´ıgitos decimales requiere de reglas mas complejas, las cuales deben ser memorizadas
• Sin embargo, cuando queremos sumar grandes n´umeros es m´as f´acil la representaci´on por d´ıgitos decimales, debido al principio basado en el peso relativo de la posici´on de cada d´ıgito dentro del n´umero.
Programas (1/2)
Programar:
Es b´asicamente estructurar datos y construir algoritmos.
Programas:
• Son formulaciones concretas de algoritmos abstractos, basados en representaciones y estructuras espec´ıficas de datos.
• Representan una clase especial de algoritmos capaces de ser ejecutados por computadores.
• Un computador, es capaz de seguir instrucciones en lenguaje de m´aquina (instrucciones oscuras y desalentadoras).
Programas (2/2)
• Por tal motivo, es necesario construir lenguajes mas adecuados, que faciliten la tarea de programar un computador.
• Un lenguaje de programaci´on es una t´ecnica de notaci´on para programar, con la intenci´on de servir de veh´ıculo tanto para la expresi´on del raciocinio algor´ıtmico como para la ejecuci´on autom´atica de un algoritmo en un computador.
Tipos de Datos
• Caracteriza a un conjunto de valores al que pertenece una constante, o que pueden ser asumidos por una variable o expresi´on, o puede ser generado por una funci´on.
• Los tipos de datos simples, son grupos de valores indivisibles (c´omo los tipos de datos int, boolean, char y float del Java)
• Ejemplo: Una variable de tipo boolean puede asumir el valor verdadero o falso y ning´un otro valor.
• Los tipos de datos estructurados, en general definen una colecci´on de valores simples, o una composici´on de valores de tipos diferentes.
Tipos abstractos de datos (TADs) [1/2]
• Modelo matem´atico, acompa˜nado de las operaciones definidas sobre el modelo.
• Ejemplo: un conjunto de dos enteros, acompa˜nado de operaciones de adici´on, substracci´on y multiplicaci´on
• Los TADs son usados ampliamente como base para el dise˜no de algoritmos. • La implementaci´on de un algoritmo en un lenguaje de programaci´on
espec´ıfico, exige la representaci´on de TAD en t´ermino de los tipos de datos y de los operadores soportados.
Tipos abstractos de datos (TADs)[2/2]
• La representaci´on de un modelo matem´atico por un TAD es realizada mediante una estructura de datos.
• Podemos considerar a los TADs como generalizaciones de tipos de datos primitivos y los procedimientos como generalizaciones de operaciones primitivas.
• Un TAD encapsula tipos de datos. Una definici´on de los tipos y todas las operaciones quedan localizadas en una secci´on del programa.
Implementaci´
on de TADs (1/2)
• Considere una aplicaci´on que utilice una lista de enteros. Podr´ıamos definir el TAD Lista, con las siguientes operaciones:
1 Vaciar lista
2 Obtener el primer elemento de la lista: si la lista estuviera vac´ıa, entonces devolver nulo.
3 Insertar un elemento en la lista
• Hay varias opciones de estructuras de datos que permiten una implementaci´on eficiente para listas, como por ejemplo vectores. • Cada operaci´on del tipo abstracto de datos es implementada como un
Implementaci´
on de TADs (2/2)
• Cualquier modificaci´on de la implementaci´on del TAD, impacta sobre la parte encapsulada, sin causar impactos sobre las otras partes de c´odigo.
• Cada conjunto diferente de operaciones define un TAD diferente sobre el mismo modelo de datos.
• La selecci´on adecuada de la implementaci´on depende fuertemente de las operaciones a ser realizadas sobre el modelo.
Medida de tiempo de ejecuci´
on de un programa
• El dise˜no de algoritmos esta fuertemente influenciado por el estudio de sus comportamientos.
• Despu´es que un problema es analizado y se han tomado decisiones sobre el dise˜no, es necesario estudiar varias opciones de algoritmos a ser utilizados, considerando los aspectos de: tiempo de ejecuci´on y espacio ocupado. • Muchos de estos algoritmos son encontrados en ´areas como: Investigaci´on
Operativa, Optimizaci´on, Teor´ıa de Grafos, Estad´ıstica, Probabilidades, entre otras.
Tipos de problemas en an´
alisis de algoritmos
• An´alisis de un algoritmo en particular:
• ¿Cu´al es el costo de utilizar un algoritmo concreto para resolver un problema en particular?
• Caracter´ısticas a investigar:
• An´alisis del n´umero de veces que cada parte de un algoritmo debe ser ejecutada • Estudio de la cantidad de memoria que necesita.
• An´alisis de una clase de algoritmos:
• ¿Cu´al es el algoritmo de menor costo para resolver un problema en particular?
• Caracter´ısticas a investigar:
• Se debe analizar toda la familia de algoritmos para resolver el problema. • Identificar uno que sea el mejor posible.
• Fijar limites para la complejidad computacional de los algoritmos pertenecientes a la clase.
Costo de un algoritmo
• Determinar el menor costo posible para resolver problemas de una determinada clase, se tiene una medida de la dificultad inherente para resolver el problema.
• Cuando el costo de un algoritmo es igual al menor costo posible, el algoritmo es ´optimo para la medida de costo considerada.
• Pueden existir varios algoritmos para resolver el mismo problema.
• Si la misma medida de costo es aplicada a diferentes algoritmos, entonces es posible compararlos y escoger el mas adecuado.
Costo de la ejecuci´
on de un programa
• Todas las medidas son bastante inadecuadas y los resultados no deben ser generalizados jam´as:
• Los resultados son dependientes del compilador que puede favorecer algunas construcciones en detrimento de otras.
• Los resultados dependen del hardware.
• Cuando grandes cantidades de memoria son utilizadas, las medidas de tiempo pueden depender de este aspecto.
• A pesar de esto, hay argumentos a favor de que se obtengan medidas reales del tiempo
• Cuando hay algoritmos distintos para resolver un mismo problema, todos con un costo de ejecuci´on en el mismo orden de magnitud
• As´ı mismo, son considerados los costos reales de las operaciones como los costos no aparentes, tales como reserva de memoria, indexaci´on, carga entre otros.
Medida de costo por medio de un modelo matem´
atico
• Usa un modelo matem´atico basado en un computador idealizado. • Se debe especificar un conjunto de operaciones y sus costos de ejecuci´on. • Es usual ignorar el costo de algunas operaciones y considerar s´olo las
operaciones mas significativas.
• Ejemplo: algoritmos de ordenaci´on. Se considerar´a el n´umero de comparaciones entre los elementos del conjunto a ser ordenado e ignoramos las operaciones aritm´eticas, de asignaci´on y manipulaci´on de ´ındices (si existiesen).
Funci´
on de complejidad
• Para medir el costo de ejecuci´on de un algoritmo es com´un definir una funci´on de costo o funci´on de complejidad f .
Definici´on:
Funci´on de complejidad de tiempo: f (n) mide el tiempo necesario para ejecutar un algoritmo en un problema de tama˜no n en un computador idealizado. Definici´on:
Funci´on de complejidad de espacio: f (n) mide la memoria necesaria para ejecutar un algoritmo en un problema de tama˜no n.
Funci´
on de complejidad
• Utilizaremos f para denotar una funci´on de complejidad de tiempo de aqu´ı en adelante.
• La complejidad de tiempo en realidad no representa el tiempo directamente, sino el n´umero de veces que una operaci´on considerada relevante es
Ejemplo: mayor elemento
• Considere un algoritmo para encontrar el mayor elemento en un vector de enteros: v[0 . . . n − 1], n ≥ 1
package Cap1; public class Max {
public static int max (int v[], int n) { int max = v[0];
for (int i = 1; i < n; i++) if (max < v[i]) max = v[i]; return max;
Ejemplo: mayor elemento
• Sea f una funci´on de complejidad tal que f (n) es el n´umero de comparaciones entre los elementos de v, si v contiene n elementos. • Luego f (n) = n − 1, para n > 0.
Ejemplo: mayor elemento
Teorema:
Cualquier algoritmo para encontrar el mayor elemento de un conjunto con n elementos, n ≥ 1, hay por lo menos n − 1 comparaciones.
Prueba.
Cada uno de los n − 1 elementos se debe examinar, mediante comparaci´on para comprobar que es menor que alg´un otro.
• Luego n − 1 comparaciones son necesarias
• El teorema anterior nos dice que, si el n´umero de comparaciones fuera utilizado como medida de costo, entonces la funci´on Max es ´optima.
Tama˜
no de la entrada de datos
• La medida de la ejecuci´on de un algoritmo depende principalmente del tama˜no de la entrada de datos.
• Es com´un considerar el tiempo de ejecuci´on de un programa como una funci´on del tama˜no de la entrada.
• Para algunos algoritmos, el costo de ejecuci´on es una funci´on particular de los datos de entrada, no del tama˜no de la entrada.
• En el caso del algoritmo Max de la funci´on de ejemplo, el costo es uniforme sobre todos los problemas de tama˜no n.
• Esto no ocurre en los algoritmos de ordenaci´on, si los datos de entrada ya estuvieran ordenados, el algoritmos puede tener que trabajar menos.
Mejor caso, peor caso y caso medio
• Mejor caso: menor tiempo de ejecuci´on sobre todas las entradas de tama˜no n. • Peor caso: mayor tiempo de ejecuci´on sobre todas las entradas de tama˜no n. • Si f es una funci´on de complejidad basada en el an´alisis del peor caso, el costo de
aplicar el algoritmo nunca ser´a mayor que f (n).
• Caso medio (caso esperado): media de los tiempos de ejecuci´on de todas las entradas de tama˜no n.
Mejor caso, peor caso y caso medio
• El an´alisis del caso esperado, se supone una distribuci´on de probabilidades sobre un conjunto de entradas de tama˜no n y el costo medio es obtenido en base a esta distribuci´on.
• El an´alisis del caso esperado (caso medio) es generalmente mucho mas dif´ıcil de realizar que el an´alisis de mejor o peor caso.
• Es com´un suponer una distribuci´on de probabilidad en la que todas las posibles entradas sean equiprobables.
Ejemplo: Registros de una archivo
• Considere el problema de acceder a los registros de un archivo. • Cada registro contiene una clave ´unica que es utilizada para recuperar
registros de un archivo.
• El problema: dada una clave cualquiera, buscar el registro que contiene esta clave.
• El algoritmo mas sencillo, es el que hace una b´usqueda secuencial. • Sea f una funci´on de complejidad tal que f (n) es el n´umero de registros
consultados del archivo (n´umero de veces que la clave de consulta es comparada con cada clave de registro) :
• Mejor caso: f (n) = 1 (el registro buscado es el primero)
• Peor caso: f (n) = n (el registro buscado es el ´ultimo o no se encuentra en el archivo.
Ejemplo: registro de un archivo
• En el estudio del caso medio, vamos a considerar que toda b´usqueda recupera un registro.
• Sea pi la probabilidad que el i-´esimo registro sea recuperado. Considerando
que para recuperar el i-´esimo registro son necesarias i comparaciones, entonces:
Ejemplo: registro de un archivo
• Para calcular f (n) basta conocer la distribuci´on de probabilidades de pi.
• Si cada registro tiene la misma probabilidad de ser accedido que otro entonces: pi = 1/n, 1 ≤ i ≤ n. En este caso:
f (n) = 1 n(1 + 2 + 3 + . . . + n) = 1 n( n(n + 1) 2 ) = n + 1 2
• El an´alisis del caso esperado revela que una b´usqueda con ´exito, examina la mitad de los registros.
Ejemplo: Mayor y menor elemento (1)
• Considere el problema de encontrar el mayor y menor elemento de un vector de enteros: v[1..n], n ≥ 1
• Un algoritmo simple puede ser derivado del algoritmo presentado en el programa para hallar el mayor elemento:
• El vector maxM in declarado localmente en el m´etodo maxM in1 es utilizado para retornar en las posiciones 0 y 1 el mayor y menor elemento del vector v respectivamente.
Ejemplo: Mayor y menor elemento (1)
package cap1;
public class MaxMin1 {
public static int [] maxMin1 (int v[], int n) { int max = v[0], min = v[0];
for (int i = 1; i < n; i++) { if (v[i] > max) max = v[i]; if (v[i] < min) min = v[i]; }
int maxMin[] = new int[2];
maxMin[0] = max; maxMin[1] = min; return maxMin;
} }
Ejemplo: Mayor y menor elemento (1)
• Sea f (n) el n´umero de comparaciones entre los elementos de v, si v contiene n elementos.
• Luego f (n) = 2(n − 1), para n > 0, para el mejor caso, peor caso y caso medio.
• MaxMin1 puede ser f´acilmente mejorado: la comparaci´on v[i] < M in s´olo es necesaria cuando las comparaci´on v[i] da falso.
Ejemplo: Mayor y menor elemento (2)
package Cap1;
public class MaxMin2 {
public static int [] maxMin2 (int v[], int n) { int max = v[0], min = v[0];
for (int i = 1; i < n; i++) { if (v[i] > max) max = v[i]; else if (v[i] < min) min = v[i]; }
int maxMin[] = new int[2];
maxMin[0] = max; maxMin[1] = min; return maxMin;
} }
Ejemplo: Mayor y menor elemento (2)
• Para esta nueva implementaci´on se tiene:
• Mejor caso: f (n) = n − 1(cuando los elementos se encuentran en orden creciente).
• Peor caso: f (n) = 2(n − 1) (cuando los elementos se encuentran en orden decreciente)
• Caso medio: f (n) = 3n/2 − 3/2.
• En el caso medio, v[i] es mayor que M ax la mitad de las veces. • Luego, f (n) = n − 1 +n−12 = 3n2 −3
Ejemplo: mayor y menor elemento (3)
• Considerando el n´umero de comparaciones realizadas, existe la posibilidad de obtener un algoritmo mas eficiente:
• Comparar los elementos de v por pares, separ´andolos en dos subconjuntos (mayores en uno y menores en otro), a un costo de dn/2e comparaciones.
• El m´aximo es obtenido del subconjunto que contiene los mayores elementos, aun costo de dn/2e − 1 comparaciones.
• El m´ınimo es obtenido del subconjunto que contiene los menores elementos, aun costo de dn/2e − 1 comparaciones.
Ejemplo: mayor y menor elemento (3)
package Cap1; public class MaxMin3 {
public static int [] maxMin3 (int v[], int n) { int max, min, FinDeBucle;
if ((n % 2) > 0) { v[n] = v[n-1]; FinDeBucle = n; } else FinDeBucle = n-1;
if (v[0] > v[1]) { max = v[0]; min = v[1]; } else { max = v[1]; min = v[0]; }
int i = 2;
while (i < FinDeBucle) { if (v[i] > v[i+1]) {
if (v[i] > max) max = v[i]; if (v[i+1] < min) min = v[i+1]; }
else {
if (v[i] < min) min = v[i]; if (v[i+1] > max) max = v[i+1]; }
i = i + 2; }
Ejemplo: mayor y menor elemento (3)
• Los elementos de v son comparados dos a dos, y los elementos mayores son comparados con Max y los elementos menores son comparados con Min. • Cuando n es impar, el elemento que esta en la posici´on v[n − 1] es duplicado
en la posici´on v[n] para evitar el tratamiento de una excepci´on. • Para esta implementaci´on,
f (n) = n 2 + n − 2 2 + n − 2 2 = 3n 2 − 2, para n > 0, para el mejor caso, peor caso y caso promedio.
Comparaci´
on entre los algoritmos MaxMin1, MaxMin2 y
MaxMin3
• La tabla presenta una comparaci´on entre los algoritmos de los programas M axM in1, M axM in2 y M axM in3, considerando el n´umero de comparaciones como medida de la complejidad.
• Los algoritmos M axM in2 y M axM in3 son superiores al algoritmo M axM in1 de forma general.
• El algoritmo M axM in3 es superior al algoritmo M axM in2 con relaci´on al peor caso y es bastante pr´oximo en cuanto al caso promedio.
Algoritmos Mejor caso Peor caso Caso promedio MaxMin1 2(n − 1) 2(n − 1) 2(n − 1) MaxMin2 n − 1 2(n − 1) 3n/2 − 3/2 MaxMin3 3n/2 − 2 3n/2 − 2 3n/2 − 2
Limite inferior - Uso de un or´
aculo
• ¿Existe la posibilidad de obtener un algoritmo M inM ax mas eficiente? • Para responder tenemos que conocer el limite inferior de esta clase de
algoritmos.
• Una de las t´ecnicas mas utilizadas: uso de un or´aculo.
• Se establece un modelo computacional que exprese el comportamiento de un algoritmo, el or´aculo informa el resultado de cada paso posible (en nuestro caso, de cada comparaci´on)
• Para calcular el l´ımite inferior, el or´aculo siempre intenta forzar que el algoritmo trabaje al m´aximo, escojiendo como resultado de la pr´oxima comparaci´on aquel que cause el mayor trabajo posible para determinar la respuesta final.
Ejemplo de uso de un Or´
aculo
Teorema:
Cualquier algoritmo para encontra el mayor y menor elemento de un cojunto con n elementos no ordenados, n ≥ 1, hace por lo menos d3n/2e − 2 comparaciones. Prueba.
La t´ecnica utilizada define un or´aculo que describe el comportamiento de un algoritmo por medio de un conjunto de n − tuplas, mas un cojunto de reglas asociadas que muestran las tuplas posibles (estados) que un algoritmo puede alcanzar a partir de una tupla dada en una ´unica comparaci´on.
Ejemplo de uso de un Or´
aculo
• Una 4 − tupla, representada por (a, b, c, d) donde los elementos: • a → nunca fueron comparados
• b → fueron vencedores y nunca perdedores en las comparaciones realizadas.
• c → fueron perdedores y nunca vencieron en las comparaciones realizadas.
Ejemplo de uso de un Or´
aculo
• El algoritmo inicia con estado (n, 0, 0, 0) y termina con el estado (0, 1, 1, n − 2)
• Despu´es de cada comparaci´on de la tupla (a, b, c, d) se consigue avanzar apenas en uno de los seis estados posibles mostrados a continuaci´on:
Ejemplo de uso de un Or´
aculo
• (a − 2; b + 1; c + 1; d) se a ≥ 2 (dos elementos son comparados) • (a − 1; b + 1; c; d) ´o (a − 1; b; c + 1; d) o (a − 1; b; c; d + 1) si a ≥ 1 (un
elemento de a comparado con uno de b o uno de c)
• (a; b − 1; c; d + 1) si b ≥ 2 (dos elementos de b son comparados) • (a; b; c − 1; d + 1) se c ≥ 2 (dos elementos de c son comparados) • El primer paso requiere necesariamente la manipulaci´on del elemento a • El camino mas r´apido para llevar a a cero requiere dn − 2e cambios de estado
y termina con una tupla (0, n/2, n/2, 0) (por medio de las comparaciones de los elementos de a dos a dos)
Ejemplo de uso de un Or´
aculo
• A continuaci´on, para reducir un componente b son necesarias dn/2e − 1 cambios de estado (m´ınimo de comparaciones necesarias para obtener el mayor elemento de b).
• Idem para c, con dn/2e − 1 cambios de estado.
• Luego, para obtener el estado (n, 1, 1, n − 2) a partir del estado (n, 0, 0, 0) son necesarias:
dn/2e + dn/2e − 1 + dn/2e − 1 = d3n/2e − 2, comparaciones
• El teorema nos dice que si un n´umero de comparaciones entre los elementos de un vector fuera utilizado como medida del costo, entonces el algoritmos
Comportamiento Asint´
otico de Funciones
• El par´ametro n proporciona una medida de la dificultad para resolver el problema.
• Para valores suficientemente peque˜nos de n, cualquier algoritmo tiene un coste peque˜no incluyendo los algoritmos ineficientes.
• La elecci´on de un algoritmo no es un problema cr´ıtico para problemas de tama˜no peque˜no
• Por lo tanto, el an´alisis de algoritmos es realizado para valores grandes de n. • Se estudia el comportamiento asint´otico de las funciones de coste.
• El comportamiento asint´otico de f (n) representa el comportamiento l´ımite de coste cuando n crece.
Dominaci´
on Asint´
otica
Definici´on:
Una funci´on f (n) domina asint´oticamente a otra funci´on g(n) si existen dos constantes positivas c y m tales que cuando n ≥ m se cumple que |g(n)| ≤ c × |f (n)|
• El an´alisis de un algoritmo generalmente s´olo tiene en cuenta apenas algunas operaciones elementales.
• La medida del coste o la medida de la complejidad, pone de manifiesto el crecimiento asint´otico de la operaci´on considerada.
Notaci´
on O
Definici´on:
Una funci´on g(n) es O(f (n)) si existen dos constantes positivas c y m tales que: g(n) ≤ cf (n), para todo n ≥ m
• Escribimos g(n) = O(f (n)) para expresar que f (n) domina asint´oticamente a g(n), y se lee g(n) es del orden m´aximo de f (n).
• Ejemplo: cuando decimos que el tiempo de ejecuci´on T (n) de un programa es O(n2), significa que
existen constantes c y m tales que, para valores de n ≥ m, T (n) ≤ cn2.
Ejemplos de notaci´
on O
• Ejemplo: g(n) = (n + 1)2.
• Luego g(n) es O(n2), cuando m = 1 y c = 4. • Debido a que: (n + 1)2≤ 4n2
para n ≥ 1 • Ejemplo: g(n) = n y f (n) = n2.
• Sabemos que g(n) es O(n2), pues para n ≥ 0, n ≤ n2
• Sin embargo, f (n) no es O(n)
• Supongamos que exista constantes c y m tales que, para todo n ≥ m, n2≤ cn.
• Luego c ≥ n para cualquier n ≥ m, y no existe una constante c que pueda ser mayor o igual a n para todo n.
Ejemplos de notaci´
on O
• Ejemplo: g(n) = 3n3+ 2n2+ n es O(n3).
• Basta mostrar que 3n3+ 2n2+ n ≤ 6n3, para n ≥ 0 .
• La funci´on g(n) = 3n3+ 2n2+ n es tambi´en O(n4), sin embargo esta afirmaci´on es mas debil que decir que g(n) es O(n3).
• Ejemplo: g(n) = log5n es O(logn).
• El logbn difiere de logcn por una constante que en nuestro caso es: logbc. • C´omo n = clogcn, tomando el logaritmo en base b en ambos lados de la
Operaciones con Notaci´
on O
• f (n) = O(f (n))
• c × O(f (n)) = O(f (n)), c es una constante • O(f (n)) + O(f (n)) = O(f (n))
• O(O(f (n))) = O(f (n))
• O(f (n)) + O(g(n)) = O(maxf (n), g(n)) • O(f (n))O(g(n)) = O(f (n)g(n))
Operaciones con Notaci´
on O
• Ejemplo: regla de suma O(f (n)) + O(g(n))
• Suponga 3 porciones de programa cuyos tiempos de ejecuci´on son: O(n), O(n2) y O(nlogn)
• El tiempo de ejecuci´on de las dos primeras porciones es: O(max(n, n2)), que es O(n2).
• El tiempo de ejecuci´on de las 3 porciones de algoritmos es: O(max(n2, nlogn)), que es O(n2).
• El producto de [log n + k + O(1/n)] por [n + O(√n)] es n log n + kn + O(√n log n).
Notaci´
on Ω
Definici´on:
Una funci´on es Ω(f (n)) si existen dos constantes c y m tales que g(n) ≥ cf (n), para todo n ≥ m.
• Especifica un l´ımite inferior para una funci´on g(n).
• Ejemplo 1: Para demostrar que g(n) = 3n3+ 2n2 es Ω(n3) basta con hacer c = 1, entonces: 3n3+ 2n2≥ n3 para n ≥ 0.
• Ejemplo 2: Sea g(n) = n, cuando n es impar (n ≥ 1) y g(n) = n2/10
cuando n es par (n ≥ 0). En este caso g(n) es Ω(n2), ya que basta
Notaci´
on Ω
• Ejemplo gr´afico de la notaci´on Ω.
• Para todos los valores mas all´a de m, el valor de g(n) esta sobre o encima del valor de cf (n).
Notaci´
on Θ
Definici´on:
Una funci´on g(n) es Θ(f (n)) si existen las constantes positivas c1, c2 y m tales
que 0 ≤ c1f (n) ≤ g(n) ≤ c2f (n), para todo n ≥ m.
Notaci´
on Θ
• Decimos que g(n) = Θ(f (n)) si existen constantes positivas c1, c2 y m tales
que, para todo valor de n ≥ m, el valor de g(n) se encuentra sobre c1f (n) y
por debajo de c2f (n).
• Esto es, para todo n ≥ m, una funci´on g(n) es igual a f (n) salvo por una constante.
Ejemplos de Notaci´
on Θ
• Sea g(n) = n2/3 − 2n, debemos demostrar que g(n) = Θ(n2).
• Se tiene que encontrar las constantes c1, c2 y m tales que:
0 ≤ c1n2≤ n2/3 − 2n ≤ c2n2 para todo n ≥ m.
• S´ı dividimos por n2 tenemos que: c
1≤13−n2 ≤ c2.
• El lado derecho de la desigualdad ser´a siempre v´alido para cualquier valor de n ≥ 1 cuando se elige c2≥ 13
• Si elegimos c1≤ 211, el lado izquierdo de la desigualdad ser´a v´alido para
cualquier valor de n ≥ 7.
• Luego, eligiendo c1= 211, c2=13 y m = 7, se verifica que
n2/3 − 2n = Θ(n2).
Clases de comportamiento Asint´
otico
• Si f es una funci´on de complejidad para un algoritmo F , entonces O(f ) es considerada como complejidad asint´otica o comportamiento asint´otico del algoritmo F .
• Una relaci´on de dominaci´on asint´otica permite comparar funciones de complejidad.
• Entretanto, si las funciones f y g dominan asint´oticamente una a otra, entonces los algoritmos asociados son equivalentes.
• En estos casos, el comportamiento asint´otico no sirve para comparar los algoritmos.
Clases de comportamiento Asint´
otico
• Por ejemplo, considere dos algoritmos F y G aplicados a la misma clase de problemas, si F lleva 3 veces el tiempo de ejecuci´on de G en ser ejecutado, esto es, f (n) = 3g(n), es decir: O(f (n)) = O(g(n)).
• Luego, el comportamiento asint´otico no sirve para comparar los algoritmos F y G porque ellos difieren apenas por una constante.
Comparaci´
on de programas
• Podemos validar programas comparando las funciones de complejidad, sin considerar las constantes de proporcionalidad.
• Un programa con tiempo de ejecuci´on O(n2) es mejor que otro de tiempo
O(n2).
• No obstante, las constantes de proporcionalidad pueden alterar esta consideraci´on.
Comparaci´
on de programas
• Ejemplo: un programa lleva 100n unidades de tiempo para ser ejecutado y otro lleva 2n2. ¿Cu´al de los dos es mejor?
• Depende del tama˜no del problema.
• Para n < 50, el programa con tiempo 2n2 es mejor que el de tiempo de ejecuci´on 100n.
• Para problemas con entrada de datos peque˜na es preferible usar un programa cuyo tiempo de ejecuci´on es O(n2).
• Entretanto, cuando n crece, el programa con tiempo de ejecuci´on O(n2) lleva mucho mas tiempo que el programa O(n).
Principales clases de problemas
• f (n) = O(1)
• Los algoritmos de complejidad O(1) son distintos de complejidad constante.
• Uso de un algoritmos independiente de n.
Principales clases de problemas
• f (n) = O(logn).
• Un algoritmo de complejidad O(logn) se dice que tiene complejidad logaritmica.
• Es t´ıpico de algoritmos que transforman un problema en problemas menores.
• Se puede considerar un tiempo de ejecuci´on menor que una constante grande.
• Cuando n es 1000, log2n ≈ 10, cuando n es 1000000, log2n ≈ 20. • Para doblar el valor de logn tenemos que considerar el cuadrado de n.
• La base de logaritmo influye muy poco en estos valores: cuando n es 1000000 el log2n es 20 y log10n es 6.
Principales clases de problemas
• f (n) = O(n)
• Un algoritmo de complejidad O(n) es llamado complejidad lineal.
• En general, un trabajo peque˜no es realizado sobre cada elemento de entrada.
• En la mejor situaci´on posible, tiene que procesar n elementos de entrada, o producir n elementos de salida.
Principales clases de problemas
• f (n) = O(nlogn)
• Se da en algoritmos que parten un problema en otros menores, resuelven cada uno de ellos de manera independiente y juntan las soluciones despu´es.
• Cuando n es 1 mill´on, nlog2n es cerca de 20 millones.
• Cuando n es 2 millones, nlog2n es cerca de 42 millones, un poco mas del doble.
Principales clases de problemas
• f (n) = O(n2)
• Un algoritmo de complejidad O(n2) es llamado de complejidad cuadr´atica.
• Ocurre cuando los items de datos son procesados en pares, muchas veces en un bucle dentro de otro.
• Cuando n es mil, el n´umero de operaciones es en el orden de un mill´on.
• Siempre que n se duplica, el tiempo de ejecuci´on es multiplicado por 4.
Principales clases de problemas
• f (n) = O(n3)
• Un algoritmo de complejidad O(n3) es llamado de complejidad c´ubica.
• Utiles apenas para resolver peque˜´ nos problemas.
• Cuando n es 100, el n´umero de operaciones esta en el orden de un mill´on.
Principales clases de problemas
• f (n) = O(2n)
• Un algoritmo de complejidad O(2n) es llamado de complejidad exponencial. • No son ´utiles desde el punto de vista pr´actico.
• Aparecen cuando se soluciona un problema empleando fuerza bruta.
• Cuando n es 20, el tiempo de ejecuci´on es cerca de un mill´on. Cuando n se duplica, el tiempo de ejecuci´on es elevado al cuadrado.
Principales clases de problemas
• f (n) = O(n!)
• Un algoritmo de complejidad O(n!) es tambi´en llamado de complejidad exponencial, a pesar de O(n!) tiene un comportamiento peor que O(2n)
• Aparecen cuando se soluciona un problema empleando fuerza bruta.
• Cuando n = 20 → 20! = 2432902008176640000, un n´umero de 19 d´ıgitos.
Algoritmos Polinomiales
• Un algoritmo exponencial tiene un tiempo de ejecuci´on en funci´on de la complejidad O(cn), c > 1.
• Un algoritmo polinomial tiene un tiempo de ejecuci´on en funci´on de la complejidad O(p(n)), donde p(n) es un polinomio.
• La diferencia entre estos dos tipos de algoritmo es significativa cuando el tama˜no del problema a resolver crece.
• Por eso, los algoritmos polinomiales son m´as utiles en la pr´acica que los exponenciales, ya que estos en la practica, son variaciones simples de una b´usqueda exhaustiva.
• Los algoritmos polinomiales son obtenidos mediante un estudio mas profundo de la estructura del problema.
Algoritmos Polinomiales
• Un problema es considerado:
• Intratable: si no existe un algoritmo polinomial para resolverlo.
Algoritmos polinomiales vs algoritmos exponenciales
• La diferencia entre algoritmos polinamiales eficientes y algoritmos exponenciales ineficientes posee varias excepciones.
• Ejemplo: un algoritmo con funci´on de complejidad f (n) = 2n es m´as rapido
que un algoritmo g(n) = n5 para valores de n menores o iguales a 20.
• Tambi´en existen algoritmos exponenciales que son muy ´utiles en la pr´actica. • Ejemplo: el algoritmo simplex para programaci´on lineal tiene una complejidad
de tiempo exponencial para el peor caso, pero en la pr´actica se ejecuta mucho mas r´apido.
• Por desgracia, tales ejemplos no aparecen con frecuencia en la pr´actica, y muchos algoritmos exponenciales conocidos no son muy ´utiles.
Ejemplo de un algoritmo exponencial
• Un agente viajero desea visitar n ciudades de tal forma que su viaje inicie y termine en una misma ciudad, y cada ciudad debe ser visitada una ´unica vez.
• Supongamos que siempre existe un camino entre dos ciudaddes cualesquiera, el problema es encontrar la menor ruta para el viaje.
• La figura ilustra un ejemplo para cuatro ciudades: c1, c2, c3, c4, los n´umeros sobre los arcos indican la
distancia entre las ciudades
• El recorrido < c1, c3, c4, c2, c1> es una soluci´on para el problema, cuyo recorrdio total tiene una
Ejemplo de un algoritmo exponencial
• Un algoritmo simple seria recorrer todas las rutas y seleccionar la menor de ellas.
• Existen (n − 1)! rutas posibles y la distancia total recorrida en cada ruta realiza n sumas, luego el n´umero total de sumas es n!
• Para el ejemplo anterior tendremos24 sumas.
• Ahora supongamos que tenemos 50 ciudades, el n´umero de adiciones ser´ıa 50! ≈ 1064.
• En un computador que ejecuta 109sumas por segundo, el tiempo total para resolver el problema con 50
ciudades, ser´ıa mayor que 1045siglos, s´olo para realizar las sumas.
• El problema del agente viajero aparece con frecuencia en problemas relacionado con el transporte, tambi´en en aplicaciones importantes relacionadas con el recorrido de los brazos robotizados.
T´
ecnicas de an´
alisis de algortimos
• Determinar el tiempo de ejecuci´on exacto de un programa puede ser un problema matem´atico complejo.
• Determinar el orden del tiempo de ejecuci´on, sin preocupaci´on del valor de la constante, puede ser una tarea mas simple.
• El an´alisis utiliza t´ecnicas de matem´atica discreta entre las que se encuentran el conteo o enumeraci´on de un conjunto:
• manejo de sumas,
• productos,
• permutaciones,
• factoriales,
• coeficientes binomiales,
An´
alisis de Tiempo de Ejecuci´
on
• Sentencia de asignaci´on, de lectura o de escritura: O(1).
• Secuencia de sentencias, esta determinada por el mayor tiempo de ejecuci´on de cualquier comando de la secuencia.
• Sentencia de desici´on, tiempo de ejecuci´on de las setencias que se ejecutan dentro de la estructura de control mas el tiempo necesario para evaluar la condici´on.
• Bucles, se suma el tiempo de ejecuci´on del cuerpo del bucle mas el tiempo de evaluaci´on de la condici´on de terminaci´on (generalmente O(1) ), multiplicado por el n´umero de iteraciones.
An´
alisis de Tiempo de Ejecuci´
on
• Procedimientos no recursivos, cada uno debe ser calculado de manera separada uno a uno, iniciando con aquellos que no llaman a otros procedimientos. Luego se eval´uan los procedimientos que llaman a los ya calculados con anterioridad. El proceso se repite hasta llegar al programa principal.
• Procedimientos recursivos, asociado a una funci´on de complejidad f (n) desconocida, en donde n mide el tama˜no de los argumentos en cuesti´on.
Procedimiento no recursivo
Algoritmo para ordenar los n elementos de un conjunto v en orden ascendente.
package Cap1;
public class Ordenacion {
public static void ordena (int v[], int n) { for (int i = 0; i < n - 1; i++) {
int min = i;
for (int j = i + 1; j < n; j++) if (v[j] < v[min])
min = j;
/* @{ intercambia v[min] y v[i]}@ */ int x = v[min];
v[min] = v[i]; v[i] = x; }
An´
alisis de un procedimiento no recursivo
• Selecciona el menor elemento del conjunto.
• Intercambia este elemento con el primer elemento v[0].
• Se deben repetir ambas operaciones para los n − 1 elementos restantes, luego con los n − 2 elementos restantes y as´ı sucesivamente hasta que quede un elemento.
An´
alisis de un procedimiento no recursivo
Bucle interno:
• Contiene un comando de decisi´on, con un sentencia de asignaci´on. Ambos tienen un tiempo constante en ser ejecutados.
• En cuanto al cuerpo del comando de decisi´on, debemos considerar el peor caso, asumiendo que siempre puede ser ejecutado.
• El tiempo para incrementar el indice y validar su condici´on de terminaci´on es O(1).
• El tiempo combinado para ejecutar una vez el bucle es O(max(1, 1, 1)) = O(1), seg´un la regla de suma para la notaci´on O.
• Como el n´umero de iteraciones es n − i, el tiempo de ejecuci´on en el bucle es O((n − i) × 1) = O(n − i), deacuerdo a la regla del producto para la notaci´on O.
An´
alisis de un procedimiento no recursivo
Bucle externo:
• Contiene, adem´as del bucle interno, cuatro comandos de asignaci´on: O(max(1, (n − i), 1, 1, 1)) = O(n − i)
• La l´ınea (1) es ejecutada n − 1 veces, y el tiempo total para ejecutar el programa esta limitado por el producto de una constante por la sumatoria de (n − i):
n−1 X 1 (n − i) =n(n − 1) 2 = n2 2 − n 2 = O(n 2)
• Si consideramos el n´umero de comparaciones c´omo medida de costo relevante, el programa realiza (n2)/2 − n/2 comparaciones para ordenar n elementos.
Procedimiento recursivo
Busqueda (n) ; (1) if n <= 1
(2) then ’inspeccione elemento’ y termine else begin
(3) para cada uno de los n elementos ’inspecione elemento’ ;
(4) Busqueda(n/3) ;
end;
• Para cada procedimiento recursivo es asociada una funci´on de complejidad f (n) desconocida, donde n mide el tama˜no de los argumentos para el procedimiento.
• Obtenermos una ecuaci´on de recurrencia para f (n).
• Ecuaci´on de recurrencia: manera de definir una funci´on por una expresi´on en la que se encuentra incluida la misma funci´on.
An´
alisis de un procedimiento recursivo
• Sea T (n) una funci´on de complejidad que represente el n´umero de veces que se ha examinado los n elementos de un conjunto.
• El costo de ejecuci´on de las l´ıneas (1) y (2) es O(1), y de la l´ınea (3) es exactamente n.
• Usaremos una ecuaci´on de recurrencia para determinar el n´umero de llamadas recursivas.
• El termino T (n) es especificado en funci´on de los terminos anteriores: T (1), T (2), . . . , T (n − 1).
• T (n) = n + T (n/3), T (1) = 1 (para n = 1 hacemos una inspecci´on).
• Por ejemplo, T (3) = T (3/3) + 3 = 4, T (9) = T (9/3) + 9 = 13, y as´ı en adelante.
• Para calcular un valor de la funci´on siguiendo la definici´on, son necesarios k − 1 pasos para calcular el valor de T (3k).
Ejemplo de resoluci´
on de ecuaci´
on de recurrencia
• Sustituiremos los terminos T (k), k < n, hasta que todos los terminos T (K), k > 1, sean sustituidos por formulas contiendo apenas T (1).
T (n) = n + T (n/3) T (n/3) = n/3 + T (n/32) T (n/32) = n/32+ T (n/33)
. . .
T (n/3/3 . . . /3) = n/3/3 . . . /3 + T (n/3 . . . /3) • Adicionando lado a lado, tenemos
T (n) = n + n(1/3) + n(1/32) + n(1/33) + . . . + (n/3/3 . . . /3) que respresenta la suma de una serie geom´etrica de raz´on 1/3, multiplicada por
Ejemplo de resoluci´
on de ecuaci´
on de recurrencia
T (n) = n + n(1/3) + n(1/32) + n(1/33) + · · · + T (n/3/3 . . . /3)
• Si despreciamos el termino T (n/3/3 . . . /3) cuando n tiende a infinito, entonces: T (n) = n ∞ X i=0 (1/3)i= n( 1 1 −1 3 ) =3n 2
• Si consideramos el termino T (n/3/3/3 . . . /3) y denominamos x al n´umero de divisiones entre 3 del tama˜no del problema, entonces: n/3x= 1, y n = 3x. Luego x = log3n.
• Recordando que T (1) = 1, tenemos
T (n) = x−1 X i=0 n 3i+ T ( n 3x) = n x−1 X i=0 (1/3)i+ 1 ≤ n ∞ X i=0 (1/3)i+ 1 =3n 2 + 1
Ejemplo de resoluci´
on de ecuaci´
on de recurrencia
Otra soluci´on:
T (n) = x−1 X i=0 n 3i + T ( n 3x) • Si x = log3n, entonces T (3nx) = 1 y, T (n) = (log3n)−1 X i=0 n 3i + 1 T (n) = n(1 − ( 1 3) log3n) (1 −13) + 1 = 3n 2 − 1 2 ,