Orden en la sala! Herman Schinca Clase 17 24 de Mayo de 2011 Todos los lenguajes todos Hoy veremos algoritmos. ¿Y eso qué es? Son independientes del lenguaje en que se implementen. Son independientes de la existencia de las computadoras. Orden: ingredientes Un tipo de dato (int, char, float, bool) + Una relacion de orden sobre ese tipo (menor, mayor, más lindo, R(x,y)) Ordenando arreglos Problema: Tengo un arreglo de números enteros y los quiero ordenar siguiendo algún criterio. Por ejemplo, de menor a mayor. ¿Ideas? Vago Sort Me fijo si ya está ordenado. Si lo está, genial. Sino, aduzco que hubo un problema con el sistema operativo :-P. Bogo Sort Me fijo si ya está ordenado. Si lo está, genial. Sino, lo mezclo al “azar” y vuelvo a empezar. ¿Termina?¿Es un “buen” algoritmo? ¿Qué significa que sea bueno? ¿Cuál es la moral de los algoritmos? 3 Ejes A la hora de pensar un algoritmo debo tener en cuenta (al menos) 3 cuestiones imprescindibles: 1. Terminación 2. Correctitud 3. Complejidad/Eficiencia Hay diversas técnicas particulares pero, en general, se trata de problemas ¡no decidibles! 3 Ejes En la materia no veremos en profundidad dichas técnicas formales. Sin embargo, es una buena práctica el pensar si el algoritmo que tenemos en mente satisface nuestras necesidades: termina, hace lo que queremos que haga y puedo predecir su “rapidez”. Selection Sort En cada paso elijo el elemento más chico de lo que queda por ordenar, y lo coloco en su lugar definitivo, es decir, a continuación del que elegí en el paso anterior. Selection Sort: Ejemplo [5,4,2,1,3] → [1,4,2,5,3] → [1,2,4,5,3] → [1,2,3,5,4] → [1,2,3,4,5] → Fin Selection Sort: Código void ordenar (int* a, int tam){ for (int i = 0; i < tam-1; i++) { int k = i; for (int j = i+1; j < tam; j++) { if (a[j] < a[k]) { k = j; } } int aux = a[i]; a[i] = a[k]; a[k] = aux; } } Selection Sort: Terminación ¿Termina? ¿Siempre? ¿Por qué? Selection Sort: Correctitud ¿Qué habría que ver? 1. Termina (slide anterior). 2. Tengo exactamente los mismo elementos que al inicio, ni más, ni menos, ni otros. 3. El arreglo está ordenado. Selection Sort: Correctitud El Selection Sort es... Selection Sort: Contando Operaciones Vamos a suponer que las operaciones básicas tienen el mismo costo computacional: +,-,*,/,==,=,etc. Vamos a contar cuántas operaciones realiza el algoritmo en el peor caso. Va a depender del tamaño de la entrada. Selection Sort: Contando Operaciones void ordenar (int* a, int tam){ for (int i = 0; i < tam-1; i++) { int k = i; for (int j = i+1; j < tam; j++) { if (a[j] < a[k]) { k = j; } } int aux = a[i]; a[i] = a[k]; a[k] = aux; } } 2 op 1 op 2*(tam-1-i) op (tam-1-i) op (tam-1-i) op 3 op Selection Sort: Contando Operaciones Insertion Sort En cada paso coloco el elemento en que estoy parado en su posición definitiva, relativa a lo elementos ya visitados. Insertion Sort: Ejemplo [5,4,2,1,3] → [5,4,2,1,3] → [4,5,2,1,3] → [2,4,5,1,3] → [1,2,4,5,3] → [1,2,3,4,5] → Fin Insertion Sort: Código void insertionSort (int *a, int tam){ for (int i=0; i < tam; i++) { for (int j=i; 0 < j && a[j] < a[j-1]; j--) { int aux = a[j]; a[j] = a[j-1]; a[j-1] = aux; } } } Insertion Sort: Ejercicio Razonar acerca de su terminación. Mostrar informalmente su correctitud. Contar la cantidad de operaciones aproximada y comparar con Selection Sort. ¿Es mejor? ¿Por qué? ¿Existen casos en donde convenga usar Insertion en vez de Selection? Bubble Sort En cada paso recorro el arreglo “desde atrás” para seleccionar el elemento más pequeño que aún no ha sido ordenado. Bubble Sort: Ejemplo [5,4,2,1,3] → [1,2,5,4,3] → [1,2,3,5,4] → [1,2,3,4,5] → [1,2,3,4,5] → Fin Bubble Sort: Ejemplo Zoom In ¿Pero cómo hace para ir de [5,4,2,1,3]→[1,2,5,4,3]? [5,4,2,1,3] → [5,4,2,1,3] → [5,4,1,2,3] → [5,1,4,2,3] → [1,5,4,2,3] → ... Bubble Sort: Código void bubbleSort (int *a, const int tam){ for (int i=0; i < tam-1; i++) { for (int j=tam-1; i < j; j--) { if (a[j] < a[j-1]) { int aux = a[j]; a[j] = a[j-1]; a[j-1] = aux; } } } } Bubble Sort: Ejercicio Razonar acerca de su terminación. Mostrar informalmente su correctitud. Contar la cantidad de operaciones aproximada y comparar con Selection e Insertion Sort. ¿Es mejor? ¿Por qué? ¿Existen casos en donde convenga usar Bubble Sort? Tomar tiempos Antes de ejecutar la función que ordena: unsigned long comienzo = clock(); Luego de la llamada: unsigned long fin = clock(); Para mostrar la diferencia: printf("t: %d\n",fin-comienzo); Experimentos Generar arreglos de 10, 100, 10000 y 100000 elementos. Ordenados de menor a mayor; de mayor a menor; desordenados. Tomar tiempos para los 3 algoritmos y sacar concluciones. Experimentos: aleatoreidad Para generar valores “aleatorios” usar la función rand() que devuelve un entero entre 0 y 215-1. Pueden utilizar % para restringir los valores. Por ejemplo, quiero valores entre 0 y 9: int valor = rand() % 10; Experimentos: más aleatoreidad La función rand() utiliza una semilla. Por defecto es siempre la misma. Para generar nuevas semillas, antes de usar rand, llamamos a: srand (time(NULL)); Optimizaciones Luego de analizar los resultados de los experimentos, pensar e implementar ideas para mejorar alguno/s de los algoritmos vistos sin perder “el concepto” del mismo. Analizar su corrección y comparar tiempos para comprobar si optimizaron. Desafío Se tienen N pares, donde la primera componente es un número y la segunda es un color (rojo, azul y ámbar). Además, se encuentran ordenados según el número. Dar un algoritmo que los ordene por color (según rojo-azul-ámbar) pero manteniendo el orden entre los números de un mismo color. La cantidad de operaciones del algoritmo debe ser del orden de N. ¡Justificar TODO! Desafío: Ejemplo R=Rojo, Z=Azul, A=Ámbar (1,Z), (3,R), (4,Z), (6,A), (9,R) → (3,R), (9,R), (1,Z), (4,Z), (6,A)