Orden en la sala!
Herman Schinca
Clase 17
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?
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
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í
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] → FinSelection 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.
Selection Sort: Correctitud
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.
Selection Sort: Contando
Operaciones
void ordenar (int* a, int tam){
for (int i = 0; i < tam-1; i++) { 2 op
int k = i; 1 op
for (int j = i+1; j < tam; j++) { 2*(tam-1-i) op
if (a[j] < a[k]) { (tam-1-i) op
k = j; (tam-1-i) op
} }
int aux = a[i]; a[i] = a[k]; a[k] = aux; 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
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] → FinInsertion 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
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] → FinBubble 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:
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:
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:
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.
Desafío: Ejemplo
R=Rojo, Z=Azul, A=Ámbar (1,Z), (3,R), (4,Z), (6,A), (9,R)
→