Soluciones a los ejercicios planteados en el curso Unidad 3 - Algoritmos recursivos Lección 2 – Mecanismo de recursividad 1 Escribe un algoritmo recursivo que calcule el elemento de cardinal más elevado de un vector de datos de tipo entero. Por ejemplo, para la entrada {1, 3, 25, 9, 20} obtendremos como resultado 25. Para simplificar el algoritmo, pasaremos como parámetros el índice actual dentro del vector de números así como el número de cardinal más elevado hasta el momento max. El caso base o condición de salida es la llegada al fin del vector, en cuyo caso devolvemos simplemente el valor max obtenido hasta el momento. En el resto de casos, se compara el elemento en la posición actual del vector con max y se actualiza el valor de max si corresponde. En todo caso, se llama de nuevo a la función recursiva incrementando la posición dentro del vector de números: Algoritmo en C________________________________________________ #include <stdio.h> #include <stdlib.h> int numeros[] = {1, 5, 25, 20, 2}; int NUMS = 5; int mayor(int indice, int max) { if(indice == NUMS - 1) { return max; } else { if( numeros[indice] > max ) max = numeros[indice]; return mayor( indice + 1, max); } } [Haz clic aquí y escribe el título de la unidad didáctica] 1 int main() { int resultado = mayor(0, -1); printf("Resultado: %d", resultado); return 0; } ___________________________________________________________ 2 n El valor de x se puede definir recursivamente como: x0 = 1 xn = x * xn – 1 Implementa de forma recursivo el cálculo de x cualquier valor de X y n. n para La función recursiva recibirá dos parámetros: la base (X) y el exponente (n) 0 al que se eleva la base. En este caso, el caso base lo constituye el caso x = 1. En el resto de casos, llamamos a la función recursiva multiplicando, tal y como indica la fórmula, la base por ella misma elevada al exponente decrementado en una unidad. Algoritmo en C________________________________________________ #include <stdio.h> #include <stdlib.h> int potencia(int base, int exponente) { if(exponente == 0) { return 1; } else { return base * potencia(base, exponente - 1); } } int main() { int resultado = potencia(3, 5); printf("Resultado: %d", resultado); return 0; } ___________________________________________________________ Lección 5 – Recursividad vs. Iteración [Haz clic aquí y escribe el título de la unidad didáctica] 2 1 Reescribe el algoritmo para calcular el factorial de un número de forma iterativa. Para implementar iterativamente el algoritmo basta con preparar un bucle que multiplique el número con todos los números inferiores a él hasta llegar a 1. Algoritmo en C________________________________________________ #include <stdio.h> #include <stdlib.h> int factorial(int num) { int resultado = num; int i; for(i = num - 1;i > 0; i--) { resultado *= i; } return resultado; } int main() { printf("El factorial del número 7 es %d\n", factorial(7)); return 0; } ___________________________________________________________ Unidad 4 - Algoritmos de búsqueda Lección 2 – Búsqueda secuencial 1 Reescribe la función busquedaSecuencial para que devuelva, en lugar de Verdadero, la posición del dato buscado si éste se localiza. ¿Qué valor podemos devolver para indicar que no se encontró el valor buscado? Recordemos que para comprobar cuando ha llegado al final del vector, el algoritmo mantiene en la variable pos la posición actual dentro del mismo. De modo [Haz clic aquí y escribe el título de la unidad didáctica] 3 que simplemente sustituyendo Verdadero por pos podremos devolver la posición en la que se ha encontrado el elemento. No tan trivial resulta la elección del valor a devolver si no se encuentra el dato buscado. Ya no es posible devolver Falso* puesto que es un valor booleano y el tipo de dato devuelto ahora es entero (pos es un valor entero). Podríamos elegir el valor 0 pero es necesario recordar que en la mayoría de lenguajes el primer elemento de un vector se representa con el índice 0, de modo que ¿qué pasaría si el valor buscado se encontrase en la primera posición, de índice 0? La solución idónea puede ser devolver el valor -1, que es de tipo entero. Los elementos del vector siempre son números enteros positivos lo cual elimina cualquier posible ambigüedad al respecto: Algoritmo en pseudocódigo______________________________________ funcion busquedaSecuencial (vector, dato) pos := 0 tam := tamaño(vector) mientras pos < tam si (vector[pos] = dato) entonces devolver pos fin si pos = pos + 1 fin mientras devolver -1 fin funcion ___________________________________________________________ * En realidad generalmente es posible ya que en muchos lenguajes Falso se convertirá al valor 0 (entero) si es necesario. Pero aquí buscamos un algoritmo teóricamente correcto. Lección 3 – Búsqueda binaria 1 Reescribe el algoritmo de búsqueda binaria de forma recursiva. Algoritmo en pseudocódigo______________________________________ funcion busquedaBinaria(vector, izq, der, dato) centro := (izq + der) / 2 si izq > der entonces devolver -1 sino si (vector[centro] = dato) entonces devolver centro sino si (dato < vector[centro]) entonces [Haz clic aquí y escribe el título de la unidad didáctica] 4 sino fin si fin funcion devolver busquedaBinaria(vector, izq, centro - 1, dato) devolver busquedaBinaria(vector, centro + 1, der, dato) La llamada inicial a la función será la siguiente: busquedaBinaria(vector, 0, tamaño(vector) – 1, dato) ___________________________________________________________ Unidad 5 - Algoritmos de ordenación Midiendo la eficiencia de los algoritmos Para medir la eficiencia de estos algoritmos y poder compararlos entre sí, o comparar la eficiencia para distintos tipos de entrada (vectores ordenados, no ordenados, casi ordenados…) podemos utilizar la función clock incluída en time.h. clock() devuelve los ‘ticks’ transcurridos desde el inicio del programa, en milisegundos. Si haces una llamada a clock() justo antes de llamar al algoritmo de ordenación y otra llamada justo después, podrás obtener el tiempo de ejecución del algoritmo restando al valor obtenido en la segunda llamada el obtenido en la primera: #include <time.h> … long tiempo = clock(); ordena(); tiempo = clock() – tiempo; printf(“El tiempo en milisegundos es %ld”, tiempo); … Ten en cuenta que para vectores de entrada pequeños y/o ordenadores rápidos (cualquiera de hoy en día) el tiempo devuelto puede ser 0 milisegundos, lo cual sirve de poca ayuda. Prueba a trabajar con vectores de entrada más grandes. Mostrando el vector en pantalla Puedes utilizar esta función para mostrar en pantalla un vector de tipo int. Te será útil para observar el estado del vector antes y después de ser ordenado: void imprimeContenidoVector() { int i; printf("El vector antes de ser ordenado\n"); printf("{"); for(i = 0;i < tamanoVector; i++ ) { printf("%d", vector[i]); if( i < tamanoVector - 1) { [Haz clic aquí y escribe el título de la unidad didáctica] 5 } printf(", "); } printf("}\n"); } Ten en cuenta que hace uso de las variables globales vector y tamanoVector que deberán existir y estar convenientemente inicializadas. Con objeto de simplificar el código trabajaremos con variables globales para representar el vector de datos a ordenar. Lección 2 – Inserción directa 1 Implementa el algoritmo de inserción directa en un lenguaje de tu elección y pruébalo con distintas entradas. Comprueba su eficiencia con vectores ordenados, casi ordenados y no ordenados. Algoritmo en C________________________________________________ #include <stdio.h> #include <stdlib.h> int vector[] = {10, 99, 35, 25, 3, 7, 80, 22, 45, 23}; int tamanoVector = 10; void ordenaInsercionDirecta() { int indice; for(indice = 0; indice < tamanoVector; indice++) { int elemento = vector[indice]; int pos = indice - 1; while ((pos >= 0) && (elemento < vector[pos])) { vector[pos + 1] = vector[pos]; pos = pos - 1; } vector[pos + 1] = elemento; } [Haz clic aquí y escribe el título de la unidad didáctica] 6 } int main() { imprimeContenidoVector(); ordenaInsercionDirecta(); imprimeContenidoVector(); return 0; } ___________________________________________________________ Lección 3 – Inserción binaria 1 Implementa el algoritmo de inserción binaria en un lenguaje de tu elección y compara su eficiencia con la del algoritmo de inserción binaria para datos ordenados y aleatorios. Algoritmo en C________________________________________________ #include <stdio.h> #include <stdlib.h> int vector[] = {10, 99, 35, 25, 3, 7, 80, 22, 45, 23}; int tamanoVector = 10; void ordenaInsercionBinaria() { int indice; for(indice = 1; indice < tamanoVector; indice++) { int elemento = vector[indice]; int bajo = 0; int alto = indice - 1; int pos; while(bajo <= alto) { int medio = (alto + bajo) / 2; if(elemento < vector[medio]) { alto = medio - 1; } else { bajo = medio + 1; } } for(pos = indice - 1;pos >= bajo; pos--) [Haz clic aquí y escribe el título de la unidad didáctica] 7 { vector[pos + 1] = vector[pos]; } vector[bajo] = elemento; } } int main() { imprimeContenidoVector(); ordenaInsercionBinaria(); imprimeContenidoVector(); return 0; } ___________________________________________________________ Lección 4 – Selección directa 1 Implementa el algoritmo de selección directa en un lenguaje de tu elección. Algoritmo en C________________________________________________ #include <stdio.h> #include <stdlib.h> int vector[] = {10, 99, 35, 25, 3, 7, 80, 22, 45, 23}; int tamanoVector = 10; void ordenaSeleccionDirecta() { int indice; for(indice = 0; indice < tamanoVector - 1; indice++ ) { int pos; int menor = indice; for(pos = indice + 1; pos < tamanoVector; pos++) { if(vector[pos] < vector[menor]) { menor = pos; } } if(menor != indice) { int tmp = vector[indice]; [Haz clic aquí y escribe el título de la unidad didáctica] 8 vector[indice] = vector[menor]; vector[menor] = tmp; } } } int main() { imprimeContenidoVector(); ordenaSeleccionDirecta(); imprimeContenidoVector(); return 0; } ___________________________________________________________ Lección 5 – Algoritmo de la burbuja 1 Implementa el algoritmo de la burbuja en un lenguaje de tu elección y pruébalo para distintos tipos de vectores de entrada. Algoritmo en C________________________________________________ #include <stdio.h> #include <stdlib.h> int vector[] = {10, 99, 35, 25, 3, 7, 80, 22, 45, 23}; int tamanoVector = 10; void ordenaBurbuja() { int indice; for(indice = 0; indice < tamanoVector; indice++ ) { int pos; for(pos = tamanoVector - 1; pos > indice; pos-- ) { if(vector[pos] < vector[pos - 1]) { int tmp = vector[pos]; vector[pos] = vector[pos - 1]; vector[pos - 1] = tmp; } } } } [Haz clic aquí y escribe el título de la unidad didáctica] 9 int main() { imprimeContenidoVector(); ordenaBurbuja(); imprimeContenidoVector(); return 0; } ___________________________________________________________ Lección 6 – Algoritmo de la burbuja mejorado 1 Implementa el algoritmo de la burbuja mejorado en un lenguaje de tu elección y compara su eficiencia con el algoritmo de la burbuja. Dado que no existe un tipo booleano en C, utilizaremos una variable de tipo entero cuyo valor estableceremos en 0 para indicar el valor falso y en 1 para indicar el valor verdadero. Algoritmo en C________________________________________________ #include <stdio.h> #include <stdlib.h> int vector[] = {10, 99, 35, 25, 3, 7, 80, 22, 45, 23}; int tamanoVector = 10; void ordenaBurbujaMejorado() { int ORDENADO = 0; int indice = 1; while((indice < tamanoVector) && !ORDENADO) { int pos; ORDENADO = 1; for(pos = tamanoVector - 1; pos >= indice; pos-- ) { if(vector[pos] < vector[pos - 1]) { int tmp = vector[pos]; vector[pos] = vector[pos - 1]; vector[pos - 1] = tmp; ORDENADO = 0; } } indice += 1; } [Haz clic aquí y escribe el título de la unidad didáctica] 10 } int main() { imprimeContenidoVector(); ordenaBurbujaMejorado(); imprimeContenidoVector(); return 0; } ___________________________________________________________ Unidad 5 – Algoritmos de mezcla Lección 2 – Mezcla simple 1 El algoritmo presentado es una implementación genérica y simplificada. ¿Puedes identificar en qué circunstancias falla? (Pon a prueba el funcionamiento del pseudocódigo con pequeñas listas de números que simulen ser ficheros, tal y como se hace en el siguiente ejemplo) Tal y como está implementado, se producirían fallos si los archivos no contienen ningún dato o si sólo uno de ellos contiene datos en cuyo caso no se escribiría el primero de los datos. Unidad 6 – Algoritmos heurísticos Lección 1 – Búsqueda exhaustiva 1 Escribe un algoritmo basado en la búsqueda exhaustiva que muestre en pantalla los divisores enteros de un número. Pruébalo con distintas entradas como 1, 5, 123, 65535, 1024768… Fíjate que hemos implementado el algoritmo de forma más sencilla que en el pseudocódigo de la lección, donde se muestra un algoritmo genérico; por ejemplo, esSolución está representado por la sentencia if((numero % i) == 0) En esta sentencia comprobamos si al dividir numero entre i el resto es 0 (el operador módulo efectúa esta operación). En tal caso, podemos afirmar que i es un divisor de numero. [Haz clic aquí y escribe el título de la unidad didáctica] 11 Algoritmo en C________________________________________________ #include <stdio.h> #include <stdlib.h> void divisoresEnteros(int numero) { int i; for(i = 1; i < numero; i++) { if((numero % i) == 0) { printf("Divisor de %d: %d\n", numero, i); } } } int main() { divisoresEnteros(123235); return 0; } ___________________________________________________________ [Haz clic aquí y escribe el título de la unidad didáctica] 12