Índice Recursión 3 Algoritmo Divide y Vencerás 4 Ejemplo 5 Iteración 6 Comparación de Bucles while, for y do-while 6 Estructura de Iteración while Sintaxis Ejemplo 7 Estructura de iteración for Sintaxis Ejemplo 8 Estructura de iteración do-while Sintaxis Ejemplo 9 Recursión en Comparación con Iteración 10 ¿Cuáles son las razones para elegir la recursión? Bibliografía 11 Página 2 Recursión Función Recursiva Una función recursiva es una unción que se llama a sí misma, ya sea directa, o indirecta a través de una función. La función, sabe sólo como resolver el caso más simple (base case). Si la función es llamada con base case, la función simplemente regresara un resultado. Si es llamada con un caso más complejo, la función divide dicho problema en dos partes: una parte que la función ya sabe como ejecutar, y una parte que la función no sabe como ejecutar. Para hacer factible la recursión, esta última parte debe de parecerse al problema original, pero más simple o una versión ligeramente más pequeña del problema original. Dado que este nuevo problema aparenta o se ve similar al problema original, la función llama a una copia nueva de sí misma, para que empiece a trabajar sobre el problema más pequeño y esto se conoce como una llamada recursiva o paso de recursión. El paso de recursión incluye la palabra reservada return, porque su resultado será combinado con la parte del problema que la función supo cómo resolver, para formar un resultado que será regresado al llamador original. El paso de recursión se ejecuta en tanto la llamada original a la función esté abierta, es decir, que no se haya terminado su ejecución. El paso de recursión puede dar como resultado muchas llamadas recursivas, conforme la función continua dividiendo cada problema sobre el cual es llamada en dos partes. A fin de que la recursión de forma eventual se termine, cada vez que la función se llame a si misma sobre una versión ligeramente más sencilla que el problema original, esta secuencia de problemas cada vez más pequeños, eventualmente deben convergir en el base case. Llegado a este punto, la función reconocerá el base case, regresa un resultado a la copia anterior de la función, y sigue a continuación una secuencia de regresos a todo lo largo de la línea, hasta llegar a la llamada original de la función, devolviendo el resultado final a main. Un requisito para que un algoritmo recursivo sea correcto es que no genere una secuencia infinita de llamadas sobre sí mismo. Cualquier algoritmo que genere una secuencia de este tipo no puede terminar nunca. En consecuencia, la definición recursiva de la función debe incluir un Case base en el que la función se defina directamente (no, recursivamente) para uno o más valores de n. Página 3 Algoritmo Divide y Vencerás En algoritmo “divide y vencerás” puede ser definido de manera recursiva, de tal modo que se llama a si mismo sobre un conjunto menor de elementos. La condición para dejar de hacer llamadas recursivas se cumple, normalmente, cuando a base de divisiones el problema se convierte en unitario (un solo elemento), base case, y puede resolverse mediante una sentencia. El diseño de algoritmos basados en esta técnica consiste en transformar (dividir) un problema de tamaño n en problemas más pequeños, de tamaño menor que n pero similares al problema original. De modo que resolviendo los subproblemas y combinando las soluciones se pueda construir fácilmente una solución del problema completo (vencerás). Normalmente, el proceso de división del problema en otros de tamaño menor va a dar lugar a problemas unitarios, base case, cuya solución es inmediata. A partir de la obtención de la solución del problema para el base case, se combinan soluciones que amplían el tamaño del problema resuelto, hasta que el problema original queda resuelto. Página 4 Ejemplo printf("Dame un numero:\t"); scanf("%d", &j); for(i=0; i<=j; i++) printf("%2d! = %ld \n", i, factorial(i)); system("PAUSE"); return 0; } long factorial(long number) { if(number <1) return 1; else return(number * factorial (number-1)); } Página 5 Iteración Un bucle (ciclo) es cualquier construcción de programa que repite una sentencia o secuencia de sentencias un número de veces. La sentencia (o grupo de sentencias) que se repiten en un bloque se denomina cuerpo del bucle y cada repetición del bucle se llama iteración del bucle. Las sentencias de iteración permiten repetir una sentencia o conjunto de ellas. Permite al programador especificar que un programa debe repetir una acción mientras alguna condición permanezca verdadera. Es lo que se denomina ejecutar un bucle. En C++ existen tres formas de iteraciones: los bucles while; do-while y for. Comparación de Bucles while, for y do-while while El uso más frecuente es cuando la repetición no está controlada por contador; el test de condición precede a cada repetición del bucle; el cuerpo del bucle puede no ser ejecutado. Se debe utilizar cuando se desea saltar el bucle si la información es falsa. for Bucle de conteo, cuando el número de repeticiones se conoce por anticipado y puede ser controlado por un contador; también es adecuado para bucles que implican control no contable del bucle con simples etapas de inicialización y de actualización; el test de la condición precede a la ejecución del cuerpo del bucle. do-while Es adecuada para asegurar que al menos se ejecute al bucle una vez. Página 6 Estructura de Iteración while La sentencia while permite ejecutar repetidamente un bloque de código mientras se cumpla una determinada condición que es chequeada antes de cada iteración. La condición puede ser falsa o verdadera. Si es verdadera, entonces se realizara la acción, esta acción se realizara de manera repetida mientras la condición sea verdadera. En algún momento la instrucción será falsa. En este punto la repetición termina, y se ejecuta la primera instrucción de seudocódigo después de esta estructura de repetición. Sintaxis while (condición_bucle) sentencia; El comportamiento o funcionamiento de una sentencia (bucle) while es: 1. Se evalúa la condición_bucle 2. Si la condición_bucle es verdadera (distinto de cero): a) La sentencia especificada, denominada cuerpo del bucle se ejecuta. b) Devuelve el control al paso 1. 3. En caso Contrario: El control se transfiere a la sentencia siguiente al bucle o sentencia while. Ejemplo #include <conio.h> #include <stdio.h> #include <stdlib.h> main() { int i,total,contador; contador=1; total=1;clrscr(); printf("Dame un numero: \t \n\n"); scanf("%d",&i); while(contador<=i) /* Esto es igual que for */ { total = total * contador; contador++; } printf("\n\nEl factorial de %d es: %d\n\n",i,total); system("PAUSE"); return 0; } Página 7 Diagrama de Flujo de la sentencia while Estructura de iteración for La estructura de repetición for maneja todos los detalles de una repetición controlada por un contador La sentencia for (bucle for) es un método para ejecutar un bloque de sentencias un número fijo de veces. Sintaxis for (inicialización; condición; incremento) sentencia; Ejemplo #include <stdio> #include <stdlib.h> main() { long int n,j=1,i; printf("Ingrese numero a calcular\t"); scanf("%ld",&n); for(i=1;i<=n;i++) /*Proceso de cálculo de factorial*/ { j=j*i; } printf("\nEl factorial del numero %.ld es igual %ld\n\n",n,j); system("PAUSE"); } Página 8 Diagrama de Flujo de la sentencia for Estructura de iteración do-while La sentencia Do-while se utiliza para especificar un bucle condicional que se ejecuta al menos una vez. Esta situación se suele dar en algunas circunstancias en las que se ha de tener la seguridad de que en determinada acción se ejecutara una o varias veces, pero al menos una vez. Sintaxis do sentencia while (expresión); La construcción do comienza ejecutando sentencia. Se evalúa a continuación expresión. Si expresión es verdadera, entonces se repite la ejecución de sentencia. Este proceso continúa hasta que expresión es falsa. Ejemplo #include <stdio.h> #include <conio.h> #include <stdlib.h> void main() { long int num,lim,res; printf("Dame un numero: \t"); scanf("%ld",&num); printf("\n"); lim=num; num=1; res=1; do{ res=res*num; num++; }while(num<=lim); printf("Resultado : %ld\n\n",res); system("PAUSE"); } Diagrama de Flujo de la sentencia do-while Página 9 Recursión en Comparación con Iteración Tanto la iteración como la recursión se basan en una estructura de control: La iteración utiliza una estructura repetitiva y la recursividad una estructura de selección. Ambas implican repetición: La iteración utiliza explícitamente una estructura repetitiva mientras que la recursión consigue la repetición mediante llamadas a funciones La iteración y la recursión y recursión implican un test de determinación (condición de salida): La iteración termina cuando la condición del bucle no se cumple mientras que la recursión termina cuando se reconoce un case base, es decir, se alcanza la condición de salida. La recursión tiene muchas desventajas. Se invoca repetidamente al mecanismo de llamadas a funciones y en consecuencia se necesita un tiempo suplementario para realizar cada llamada. Esta característica puede resultar cara en tiempo de procesador y espacio de memoria. Cada llamada recursiva produce que se realice una nueva creación y copia de las variables de la función; esto puede consumir memoria considerable e incrementar el tiempo de ejecución. La iteración se produce dentro de una función de modo que las operaciones suplementarias de las llamadas a la función y asignación de memoria adicional son omitidas. ¿Cuáles son las razones para elegir la recursión? La razón fundamental es que existen numerosos problemas complejos que poseen naturaleza recursiva y, en consecuencia, son más fáciles de implementar con algoritmos de este tipo. Sin embargo, en condiciones críticas de tiempo y de memoria; la solución a elegir, debe ser la iterativa. Página 10 Bibliografía Programación en C, 2° ed. Joyanes Aguilar, Luis. Ed. Mc Graw Hill Como programar en C++, 4° ed. Deitel, Harvey M.. Ed. Pearson Educacion Página 11