Introducción a los Algoritmos Complejidad Computacional Joemmanuel Ponce G.
¿Análisis de complejidad?
Una de las cosas más importantes a tomar en cuenta al momento de seleccionar un algoritmo es el tiempo que va a tardar en arrojar una salida.
¿Por qué es importante?
A pesar de que las computadoras de hoy en día son capaces de realizar millones de operaciones en un segundo, es muy fácil encontrar ejemplos de problemas y soluciones que tardarán años en terminar…
¿Cómo se mide?
Las computadoras de hoy en día tienen diferentes capacidades en cuanto a velocidad de procesamiento.
Saber con exactitud el tiempo que va a tardar un programa en dar una salida se vuelve una tarea muy difícil hoy en día.
¿Cómo se mide?
En vez de calcular el tiempo exacto que va a tardar nuestro algoritmo… se calcula la cantidad de operaciones en función del tamaño de la entrada (n).
¿Cómo se mide?
Por lo general para estimar el tiempo de ejecución, esta función de crecimiento se multiplica por una constante c que representa una estimación del tiempo que la computadora se tarda en realizar una operación.
¿Cómo se mide? Tamaño de la entrada Tiempo de 1 operación
Nota
En estos tiempos (2007) podemos asumir que una PC de escritorio puede realizar aproximadamente 10 9 operaciones por segundo.
Sin embargo, este indicador no es absoluto dado que unas operaciones son más lentas que otras.
Otra Nota
El tiempo exacto de ejecución de un algoritmo también depende mucho de los detalles de implementación .
EL PROBLEMA DE LA ORDENACIÓN
Un ejemplo clásico
El problema de la ordenación de números
Dado un conjunto de n números:
Un algoritmo de ordenación debe encontrar una permutación del conjunto A tal que para cualquier
(en otras palabras, ordenar del más chico al más grande)
Algoritmos de ordenación
La ordenación de datos es quizás el problema más común dentro de las Ciencias Computacionales.
Es por eso que existen bastantes algoritmos para resolver este problema.
¿Cuál es la diferencia entre ellos?
Aparte del nombre
Algoritmos de ordenación
La complejidad
No de escribirlos, sino su función de crecimiento.
Análisis de complejidad de Algoritmos de Ordenación
Para ejemplificar la función de crecimiento vamos a estudiar uno de los algoritmos más famosos de ordenación (y lento…):
Ordenación por Burbuja (BubbleSort)
Ordenación por Burbuja
La idea de la ordenación por burbuja es tomar el elemento de mayor valor de un arreglo de datos y llevarlo al final; y esto repetirlo a todos los elementos.
(se llama burbuja por que alguien se imagino que el número que se va recorriendo es como si una burbuja subiera desde el fondo del agua).
Ordenación por Burbuja
Para evitar el proceso de encontrar el máximo cada iteración, la mejor estrategia es recorrer el arreglo desde la posición 0 con un índice i.
En cada paso preguntamos si el elemento en la posición i+1 es menor al elemento i. En este caso, intercambiamos los valores.
Si seguimos este proceso observamos que el elemento mayor quedará hasta el fondo.
Ordenación por Burbuja
Supongamos el siguiente arreglo de elementos:
[1,2,15,5,7,6]
Ordenación por Burbuja
[ 1 ,2,15,5,7,6]
1>2?
Ordenación por Burbuja
[1, 2 ,15,5,7,6]
2>15?
Ordenación por Burbuja
[1,2, 15 ,5,7,6]
15>5?
Ordenación por Burbuja
[1,2,5, 15 ,7,6]
Intercambiamos (nota que el índice sigue avanzando, una vez intercambiado los valores, el índice quedará posicionado en el número 15 otra vez).
Ordenación por Burbuja
[1,2,5, 15 ,7,6]
15>7?
Ordenación por Burbuja
[1,2,5,7, 15 ,6]
Intercambiamos (y avanzamos el índice)
Ordenación por Burbuja
[1,2,5,7, 15 ,6]
15>6?
Ordenación por Burbuja
[1,2,5,7,6,15]
Intercambiamos… Podemos observar que el elemento de mayor tamaño ha quedado al fondo del arreglo.
La operación se repite hasta que se hayan “recorrido” todos los elementos.
Ejercicio
Escriba el código (o pseudocódigo) del BubbleSort
Solución
for (i=0;i<a.size()-1;i++)
for (j=i+1;j<a.size();j++)
if(a[i]>a[j]){
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
Análisis del algoritmo
Normalmente se habla de dos tipos de análisis:
Análisis del peor caso
Análisis del caso promedio
Análisis del peor caso
El análisis del peor caso es, como su nombre lo dice, es calcular su función de crecimiento dándole la peor de todas las entradas posibles.
Análisis del caso promedio
El análisis del caso promedio es, como su nombre lo dice, el promedio de cuánto tardaría nuestro algoritmo de cada una de las entradas posibles.
¿Cuál es mejor?
De los dos análisis, el del peor caso es el más fácil de razonar y es el más usado para pruebas de benchmark.
A partir de que es casi imposible probar todas las entradas posibles, los análisis de complejidad se pueden volver algo truculentos.
Análisis del algoritmo
Para analizar el costo computacional de un algoritmo, básicamente se siguen tres pasos:
Suponer el peor de los casos (en el que se ejecutan más líneas y el más grande)
A veces encontrar el peor caso no es sencillo…
Asignar un costo a cada operación o línea de código
Ver cuantas veces va a ser ejecutada cada línea de código .
Ejercicio
En el Algoritmo de Burbuja (supón un tamaño del arreglo de n) :
¿Cuál es el peor caso?
¿Cuántas veces es ejecutada cada línea?
Solución: Análisis del Peor Caso Código Costo Veces que se ejecuta for (i=0;i<n-1;i++) C1 N for (j=i+1;j<n;j++) C2 if (a[i]>a[j]){ C3 int temp=a[i]; C4 a[i]=a[j]; C5 a[j]=temp; C6 }
Por lo tanto…
La estimación del tiempo total de ejecución sería la suma del tiempo de cada una de las líneas multiplicado por su factor de costo de operación.
Por lo tanto: Código Costo Veces que se ejecuta for (i=0;i<n-1;i++) C1 N for (j=i+1;j<n;j++) C2 if (a[i]>a[j]){ C3 int temp=a[i]; C4 a[i]=a[j]; C5 a[j]=temp; C6 }
Sabemos que…
Entonces:
Concluyendo…
Para simplificar el análisis, supongamos que todas las constantes son iguales
Concluyendo
Cuando se analizan algoritmos, sólo importa el término de la función que crece más rápido y se eliminan las constantes.
Concluyendo
En nuestro caso, el término de mayor crecimiento es la n cuadrada.
Por lo que decimos que la Ordenación por Burbuja tiene una complejidad de
A recordar…
El cálculo de la complejidad tan sólo nos da una aproximación del tiempo.
Los detalles de implementación son un factor importante… aunque la complejidad sea la misma.
Calcula la complejidad… Código Costo Veces que se ejecuta for (i=0;i<n-1;i++) C1 N for (j=0;j<n;j++) C2 N 2 if (a[i]>a[j]){ C3 N 2 int temp=a[i]; C4 N 2 a[i]=a[j]; C5 N 2 a[j]=temp; C6 N 2 }
Calcula la complejidad… Código Costo Veces que se ejecuta for (i=0;i<n-1;i++) C1 N for (j=0;j<n;j++) C2 N 2 if (a[i]>a[j]){ C3 N 2 int temp=a[i]; C4 N 2 a[i]=a[j]; C5 N 2 a[j]=temp; C6 N 2 }
Ejercicio
Compara los dos algoritmos…
¿Tardarán exactamente el mismo tiempo en ejecutarse?
Ejercicio
Prueba el BubbleSort con diferentes tamaños de entrada y toma el tiempo
¿Hasta que tamaño de entrada se puede ejecutar en 1 sec?
BÚSQUEDA BINARIA
Un ejemplo más retador
¿Qué es la búsqueda binaria?
La búsqueda binaria es uno de los algoritmos más importantes dentro de las ciencias computacionales.
Básicamente nos permite encontrar un elemento dentro de una secuencia (o un arreglo), mientras sus elementos estén ordenados.
¿Qué es la búsqueda binaria?
Por claridad, llamaremos al número que deseemos encontrar como objetivo .
Llamaremos espacio de búsqueda a la secuencia (o subsecuencia, en este caso contigua) donde seguramente se encuentra el objetivo.
¿Cuál es la idea?
Inicialmente nuestro espacio de búsqueda es la secuencia completa.
La idea es ir reduciendo la cantidad de lugares donde nuestro objetivo pueda estar, es decir, ir reduciendo nuestro espacio de búsqueda.
¿Cuál es la idea?
En cada paso, el algoritmo compara el valor de en medio (mediana) del espacio de búsqueda con el objetivo.
Basado en la comparación y utilizando la propiedad de que los elementos están ordenados, se puede eliminar la mitad del espacio de búsqueda.
¿Cuál es la idea?
Si continuamos reduciendo de mitad en mitad, eventualmente llegaremos a un espacio de búsqueda de tamaño 1.
¿Qué quiere decir esto?
Hemos encontrado nuestro número
Por ejemplo
Supongamos que tenemos la siguiente secuencia:
Y buscamos el 43
-1 2 10 43 44 55 60 71 82 0 1 2 3 4 5 6 7 8
Por ejemplo
Ahora escogemos el valor de en medio del arreglo, que es el valor en el índice 4 (el punto medio entre 0 y 8 ) en este caso el 44.
Comparamos esta mediana con nuestro valor objetivo ( 43 )
Por ejemplo…
Utilizando la propiedad de ordenación del arreglo, podemos concluir que el 43 sólo puede estar en la parte izquierda de la secuencia . (43<44)
Por lo que descartamos la mitad del espacio de búsqueda que no nos sirve. (Nos quedamos con los elementos 0 a 3 ).
(Nota: Solo llevamos una operación)
43 -1 2 10 43 44 55 60 71 82 0 1 2 3 4 5 6 7 8
Por ejemplo 43
El proceso se repite. 43>10 por lo tanto tomamos la mitad de la derecha (elemento en la posición 3).
-1 2 10 43 0 1 2 3
Por ejemplo
En 3 operaciones encontramos un elemento en un arreglo ordenado de tamaño 8 .
43
Ejercicio…
¿Cuál es el peor caso de una Búsqueda Binaria?
Cuándo el elemento a buscar no se encuentra en el arreglo hace la mayor cantidad de preguntas.
Ejercicio…
Implementa una Búsqueda Binaria sobre un arreglo de enteros que regrese el índice de la posición donde se encuentra el objetivo.
Si el elemento no está en el arreglo, regresar -1.
Analiza: ¿Cuál es la condición de paro del ciclo?
Ejercicio
int binSearch(int[] a, int x){
int i=0;
int j=a.length-1;
int m;
while(i<=j){
m=(i+j)/2;
if(a[m]==x)
return m;
else if(x<a[m])
j=m-1;
else
i=m+1;
}
return -1;
}
¿CUÁL ES LA COMPLEJIDAD DE LA BÚSQUEDA BINARIA?
Análisis de Complejidad
Complejidad de la búsqueda binaria
La complejidad de la búsqueda binaria no es tan intuitiva como las revisadas anteriormente.
Antes de responder debemos analizar detenidamente el algoritmo ¿Qué sucede con el tamaño del espacio de búsqueda en cada paso?
Ejemplo…
Si n=10 esto es lo que sucede:
Complejidad de la búsqueda binaria
Es dividido a la mitad…
Entonces la pregunta clave es: ¿Cuántas veces puedo dividir por la mitad a N ?
Ejemplo…
Si viéramos al revés el proceso:
Ejemplo…
Podemos decir que el problema se trata de encontrar una x tal que: (Observa que x se convierte en el número de pasos realizados).
Conclusión
La búsqueda binaria tiene una complejidad de:
Recuerda que lo que nos interesa es la función de crecimiento, por lo que la base del logaritmo se omite.
Observaciones
El logaritmo es una función creciente muy lenta .
Para encontrar en un dato en una lista de un millón de datos ordenados se ocupan a lo más 21 comparaciones.
Observaciones
Si pudieras tener una lista con información de todas las personas del mundo tardarías a lo más 35 pasos .
Tablas comparativas…
Tiempo aproximado que se tardaría si n=100
Complejidad Tiempo 10 -7 segundos 10 -6 segundos 10 -5 segundos 10 -4 segundos 1 segundo 3 minutos 10 14 años 10 142 años
Problema Tercias (OMI 2007)
Descripción :
Se dice que 3 números a , b , y c están en sucesión aritmética si, a < b < c , y c - b = b - a. Por ejemplo los números 1, 2 y 3 están en sucesión aritmética, los números 2, 20 y 38 también lo están. Pero los números 2, 3 y 20 no lo están.
Determinar si 3 números están en sucesión aritmética es una tarea simple, pero dado un conjunto de números determinar cuántos de ellos están en sucesión aritmética es algo un poco más difícil.
Problema Tercias (OMI 2007)
Problema:
Debes escribir un programa que lea un conjunto de números distintos e imprima en pantalla cuantas tercias de esos números están en sucesión aritmética.
Tu programa deberá leer del teclado de la PC los siguientes datos:
En la primera línea el número 0 < N ≤ 7,000 que representa la cantidad de números en el conjunto.
Cada una de las siguientes N líneas contendrá un número del conjunto el cuál será un entero mayor a 0 y menor o igual a 1,000,000,000, además, estos números estarán ordenados de manera creciente.
Problema Tercias (OMI 2007)
Ejemplo:
Entrada Salida 5 1 2 3 20 38 2
Problema Tercias (OMI 2007)
Explicación:
En el ejemplo anterior se tiene un conjunto con 5 números, con estos 5 números se pueden formar las siguientes tercias:
(1,2,3)
(1,2,20)
(1,2,38)
(1,3,20)
(1,3,38)
(1,20,38)
(2,3,20)
(2,3,38)
(2,20,38)
(3,20,38)
De las tercias anteriores sólo las tercias (1,2,3) y (2,20,38) están en sucesión aritmética, por lo tanto la respuesta es 2.
Problema Tercias (OMI 2007)
Requerimientos de ejecución:
Obtendrás 10 puntos por cada caso resuelto.
Para obtener puntos en este problema, además de entregar la solución correcta tu programa deberá ejecutarse en un tiempo menor a 1 segundo.
4 comments
Comments 1 - 4 of 4 previous next Post a comment