Está en la página 1de 21

Recursividad -> El rea de la programacin es muy amplia y con muchos detalles.

Los programadores necesitan ser capaces de resolver todos los problemas que se les presente a travs del computador aun cuando en el lenguaje que utilizan no haya una manera directa de resolver los problemas. En el lenguaje de programacin C, as como en otros lenguajes de programacin, se puede aplicar una tcnica que se le dio el nombre de recursividad por su funcionalidad. Esta tcnica es utilizada en la programacin estructurada para resolver problemas que tengan que ver con el factorial de un nmero, o juegos de lgica. Las asignaciones de memoria pueden ser dinmicas o estticas y hay diferencias entre estas dos y se pueden aplicar las dos en un programa cualquiera. 1.-Recursividad: La recursividad es una tcnica de programacin importante. Se utiliza para realizar una llamada a una funcin desde la misma funcin. Como ejemplo til se puede presentar el clculo de nmeros factoriales. l factorial de 0 es, por definicin, 1. Los factoriales de nmeros mayores se calculan mediante la multiplicacin de 1 * 2 * ..., incrementando el nmero de 1 en 1 hasta llegar al nmero para el que se est calculando el factorial. El siguiente prrafo muestra una funcin, expresada con palabras, que calcula un factorial. "Si el nmero es menor que cero, se rechaza. Si no es un entero, se redondea al siguiente entero. Si el nmero es cero, su factorial es uno. Si el nmero es mayor que cero, se multiplica por l factorial del nmero menor inmediato." Para calcular el factorial de cualquier nmero mayor que cero hay que calcular como mnimo el factorial de otro nmero. La funcin que se utiliza es la funcin en la que se encuentra en estos momentos, esta funcin debe llamarse a s misma para el nmero menor inmediato, para poder ejecutarse en el nmero actual. Esto es un ejemplo de recursividad. La recursividad y la iteracin (ejecucin en bucle) estn muy relacionadas, cualquier accin que pueda realizarse con la recursividad puede realizarse con iteracin y viceversa. Normalmente, un clculo determinado se prestar a una tcnica u otra, slo necesita elegir el enfoque ms natural o con el que se sienta ms cmodo. Claramente, esta tcnica puede constituir un modo de meterse en problemas. Es fcil crear una funcin recursiva que no llegue a devolver nunca un resultado definitivo y no pueda llegar a un punto de finalizacin. Este tipo de recursividad hace que el sistema ejecute lo que se conoce como bucle "infinito". Para entender mejor lo que en realidad es el concepto de recursin veamos un poco lo referente a la secuencia de Fibonacci. Principalmente habra que aclarar que es un ejemplo menos familiar que el del factorial, que consiste en la secuencia de enteros. 0,1,1,2,3,5,8,13,21,34,..., Cada elemento en esta secuencia es la suma de los precedentes (por ejemplo 0 + 1 = 0, 1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, ...) sean fib(0) = 0, fib (1) = 1 y as sucesivamente, entonces puede definirse la secuencia de Fibonacci mediante la definicin recursiva (define un objeto en trminos de un caso ms simple de s mismo): fib (n) = n if n = = 0 or n = = 1 fib (n) = fib (n - 2) + fib (n - 1) if n >= 2 Por ejemplo, para calcular fib (6), puede aplicarse la definicin de manera recursiva para obtener: Fib (6) = fib (4) + fib (5) = fib (2) + fib (3) + fib (5) = fib (0) + fib (1) + fib (3) + fib (5) = 0 + 1 fib (3) + fib (5) 1. + fib (1) + fib (2) + fib(5) = 4. + 0 + 1 + fib (2) + fib (3) = 5 + fib (0) + fib (1) + 1. + 1 + fib(0) + fib (1) + fib (5) = fib (3) = 2. + 0 + 1 + fib(5) = 3 + fib (3) + fib (4) = 5. + 0 + 1 + fib (1) + fib (2) = 6 + 1 + fib (0) + fib (1) = 3 + 1 + fib (0) + fib (1) + fib (4) = 6. + 0 + 1 = 8 3. + fib (1) + fib (2) + fib (4) = Obsrvese que la definicin recursiva de los nmeros de Fibonacci difiere de las definiciones recursivas de la funcin factorial y de la multiplicacin. La definicin recursiva de fib se refiere dos veces a s misma. Por ejemplo, fib (6) = fib (4) + fib (5), de tal manera que al calcular fib (6), fib tiene que aplicarse de manera recursiva dos veces. Sin embargo calcular fib (5) tambin implica calcular fib (4), as que al aplicar la definicin hay mucha redundancia de clculo. En ejemplo anterior, fib(3) se calcula tres veces por separado.

Sera mucho ms eficiente "recordar" el valor de fib(3) la primera vez que se calcula y volver a usarlo cada vez que se necesite. Es mucho ms eficiente un mtodo iterativo como el que sigue parar calcular fib(n). If (n < = 1) for (i = 2; i < = n; i ++) hifib = x + lofib ; return (n); { } /* fin del for*/ lofib = 0 ; x = lofib ; return (hifib) ; hifib = 1 ; lofib = hifib ; Comprese el nmero de adiciones (sin incluir los incrementos de la variable ndice, i) que se ejecutan para calcular fib (6) mediante este algoritmo al usar la definicin recursiva. En el caso de la funcin factorial, tienen que ejecutarse el mismo nmero de multiplicaciones para calcular n! Mediante ambos mtodos: recursivo e iterativo. Lo mismo ocurre con el nmero de sumas en los dos mtodos al calcular la multiplicacin. Sin embargo, en el caso de los nmeros de Fibonacci, el mtodo recursivo es mucho ms costoso que el iterativo. 2.- Propiedades de las definiciones o algoritmos recursivos: Un requisito importante para que sea correcto un algoritmo recursivo es que no genere una secuencia infinita de llamadas as mismo. Claro que cualquier algoritmo que genere tal secuencia no termina nunca. Una funcin recursiva f debe definirse en trminos que no impliquen a f al menos en un argumento o grupo de argumentos. Debe existir una "salida" de la secuencia de llamadas recursivas. Si en esta salida no puede calcularse ninguna funcin recursiva. Cualquier caso de definicin recursiva o invocacin de un algoritmo recursivo tiene que reducirse a la larga a alguna manipulacin de uno o casos ms simples no recursivos. 3.- Cadenas recursivas: Una funcin recursiva no necesita llamarse a s misma de manera directa. En su lugar, puede hacerlo de manera indirecta como en el siguiente ejemplo: a (formal parameters) b (formal parameters) b (arguments); a (arguments); {{ .. .. } /*fin de a*/ } /*fin de b*/ En este ejemplo la funcin a llama a b, la cual puede a su vez llamar a a, que puede llamar de nuevo a b. As, ambas funciones a y b, son recursivas, dado que se llamas a s mismo de manera indirecta. Sin embargo, el que lo sean no es obvio a partir del examen del cuerpo de una de las rutinas en forma individual. La rutina a, parece llamar a otra rutina b y es imposible determinar que se puede llamar as misma de manera indirecta al examinar slo a a. Pueden incluirse ms de dos rutinas en una cadena recursiva. As, una rutina a puede llamar a b, que llama a c, ..., que llama a z, que llama a a. Cada rutina de la cadena puede potencialmente llamarse a s misma y, por lo tanto es recursiva. Por supuesto, el programador debe asegurarse de que un programa de este tipo no genere una secuencia infinita de llamadas recursivas. 4.- Definicin recursiva de expresiones algebraicas: Como ejemplo de cadena recursiva consideremos el siguiente grupo de definiciones: a. una expresin es un trmino seguido por un signo ms seguido por un trmino, o un trmino solo b. un trmino es un factor seguido por un asterisco seguido por un factor, o un factor solo. c. Un factor es una letra o una expresin encerrada entre parntesis. Antes de ver algunos ejemplos, obsrvese que ninguno de los tres elementos anteriores est definido en forma directa en sus propios trminos. Sin embargo, cada uno de ellos se define de manera indirecta. Una expresin se define por medio de un trmino, un trmino por medio de un factor y un factor por medio de una expresin. De manera similar, se define un factor por medio de una expresin, que se define por medio de un trmino que a su vez se define por medio de un factor. As, el conjunto completo de definiciones forma una cadena recursiva. La forma ms simple de un factor es una letra. As A, B, C, Q, Z y M son factores. Tambin son trminos, dado que un trmino puede ser un factor solo. Tambin son expresiones dado que una expresin puede ser un trmino solo. Como A es una expresin, (A) es un factor y, por lo tanto, un trmino y una expresin. A + B es

un ejemplo de una expresin que no es ni un trmino ni un factor, sin embargo (A + B) es las tres cosas. A * B es un trmino y, en consecuencia, una expresin, pero no es un factor. A * B + C es una expresin, pero no es un factor. Cada uno de los ejemplos anteriores es una expresin valida. Esto puede mostrarse al aplicar la definicin de una expresin de cada uno. Considrese, sin embargo la cadena A + * B. No es ni una expresin, ni un trmino, ni un factor. Sera instructivo para el lector intentar aplicar la definicin de expresin, trmino y factor para ver que ninguna de ellas describe a la cadena A + * B. De manera similar, (A + B*) C y A + B + C son expresiones nulas de acuerdo con las definiciones precedentes. A continuacin se codificar un programa que lea e imprima una cadena de caracteres y luego imprima "valida" si la expresin lo es y "no valida" de no serlo. Se usan tres funciones para reconocer expresiones, trminos y factores, respectivamente. Primero, sin embrago se presenta una funcin auxiliargetsymb que opera con tres parmetros: str, length y ppos. Str contiene la entrada de la cadena de cadena de caracteres; length representa el nmero de caracteres en str. Ppos apunta a un puntero pos cuyo valor es la posicin str de la que obtuvimos un carcter la ltima vez. Si pos < length, getsymbregresa el carcter cadena str [pos] e incrementa pos en 1. Si pos > = length, getsymb regresa un espacio en blanco. getsymb (str, length, ppos) char C; c=; char str[]; if (*ppos < length) (*ppos) ++; int length, *ppos; c = str [*ppos]; return ( c ); { else } /* fin de getsymb*/ La funcin que reconoce una expresin se llama expr. Regresa TRUE (o1) (VERDADERO) si una expresin valida comienza en la posicin pos de str y FALSE (o0) FALSO en caso contrario. Tambin vuelve a colocar pos en la posicin que sigue en la expresin de mayor longitud que puede encontrar. Suponemos tambin una funcin readstr que lee una cadena de caracteres, poniendo la cadena en str y su largo en length. Una vez descritas las funciones expr y readst, puede escribirse la rutina principal como sigue. La biblioteca estndar ctype.h incluye una funcinisalpha que es llamada por una de las funciones siguientes. # include <stdio.h> int length, pos; # include <ctype.h> readstr (str, &length); # define TRUE 1 pos = 0; # define FALSE = if (expr (str, length, &pos) = = TRUE && por >= # define MAXSTRINGSIZE 100 length) main () printf ("%s", "valida"); { else char str [MAXSTRINGSIZE]; printf ("%s", "no valida"); /* la condicin puede fallar por una de dos razones (o ambas). Si expr(str, length, &pos) = = FALSE entonces no hay una expresin valida al inicio de pos. Si pos < length puede que se encuentre una expresin valida, comenzando en pos, pero no ocupa la cadena completa */ } /*fin del main*/ Las funciones factor y term se parecen mucho a expr excepto en que son responsables del reconocimiento de factores y trmino, respectivamente. Tambin reinicializan pos en la posicin que sigue al factor o trmino de mayor longitud que se encuentra en la cadena str. Los cdigos para estas rutinas se apegan bastantes a las definiciones dadas antes. Cada una intenta satisfacer uno de los criterios para la entidad que se reconoce. Si se satisface uno de esos criterios el resultado es TRUE (VERDADERO). Si no satisface ninguno, el resultado es FALSE (FALSO). expr (str. length, ppos) /* buscando un trmino */ char str []; if (term( str, length, ppos) = = FLASE) int length, *ppos; return (FLASE); {

/* se ha encontrado un trmino; revisar el siguiente smbolo */ if (getsymb(str, length, ppos) ! = +) { /* se encontr la mayor expresin (un solo trmino). Reposicionar pos para que seale la ltima posicin de la expresin */ (*ppos) - - ; return (TRUE); } /* fin del if */ /* en este punto, se ha encontrado un trmino y su signo ms. Se deber buscar otro termino */ return (term(str, length, ppos)); } /*fin de expr */

La rutina term que reconoce trminos, es muy similar y ser presentada sin comentarios. term (str, length, ppos) char str[]; int length, *ppos; { if (factor(str, length, ppos) = = FALSE) return (FALSE); if (getsymb (str, length, ppos) ! = +) { (*ppos) -- ; return (TRUE) ; } /* fin del if */ return (factor(str, length, ppos)); } /* fin de term */ La funcin factor reconoce factores y debera ser ahora bastante sencilla. Usa el programa comn de biblioteca isalpha (esta funcin se encuentra en la biblioteca ctype.h), que regresa al destino de cero si su carcter de parmetro es una letra y cero (o FALSO) en caso contrario. factor (str, length, ppos) if ((c = getsymb (str, length, ppos)) ! = ) ) char str[]; return (isalpha(c)); int length, *ppos; return (expr(str, length, ppos) && getsymb (str, { length, ppos) == ) ); int c; } /* fin de factor */ Las tres rutinas son recursivas, dado que cada una puede llamar a s misma da manera indirecta. Pos ejemplo, si se sigue la accin del programa para la cadena de entrada " (a * b + c * d) + (e * (f) + g) " se encontrar que cada una de las tres rutinas expr, term y factor se llama a s misma. 5.- Programacin Recursiva: Es mucho ms difcil desarrollar una solucin recursiva en C para resolver un problema especfico cuando no se tiene un algoritmo. No es solo el programa sino las definiciones originales y los algoritmos los que deben desarrollarse. En general, cuando encaramos la tarea de escribir un programa para resolver un problema no hay razn para buscar una solucin recursiva. La mayora de los problemas pueden resolverse de una manera directa usando mtodos no recursivos. Sin embargo, otros pueden resolverse de una manera ms lgica y elegante mediante la recursin. Volviendo a examinar la funcin factorial. El factor es, probablemente, un ejemplo fundamental de un problema que no debe resolverse de manera recursiva, dado que su solucin iterativa es directa y simple. Sin embargo, examinaremos los elementos que permiten dar una solucin recursiva. Antes que nada, puede reconocerse un gran nmero de casos distintos que se deben resolver. Es decir, quiere escribirse un programa para calcular 0!, 1!, 2! Y as sucesivamente. Puede identificarse un caso "trivial" para el cual la solucin no recursiva pueda obtenerse en forma directa. Es el caso de 0!, que se define como 1. El siguiente paso es encontrar un mtodo para resolver un caso "complejo" en trminos de uno ms "simple", lo cual permite la reduccin de un problema complejo a uno ms simple. La transformacin del caso complejo al simple resultara al final en el caso trivial. Esto significara que el caso complejo se define, en lo fundamental, en trminos del ms simple. Examinaremos que significa lo anterior cuando se aplica la funcin factorial. 4! Es un caso ms complejo que 3!. La transformacin que se aplica al nmero a para obtener 3 es sencillamente restar 1. Si restamos 1 de 4 de manera sucesiva llegamos a 0, que es el caso trivial. As, si se puede definir 4! en trminos de 3! y, en general, n! en trminos de (n 1)!, se podr calcular 4! mediante la definicin de n! en trminos de (n 1)! al trabajar, primero hasta llegar a 0! y luego al regresar a 4!. En el caso de la funcin factorial se tiene una definicin de ese tipo, dado que: n! = n * (n 1)! As, 4! = 4 * 3! = 4 * 3 * 2! = 4 * 3 * 2 * 1! = 4 * 3 * 2 * 1 * 0! = 4 * 3 * 2] * ] = 24

Estos son los ingredientes esenciales de una rutina recursiva: poder definir un caso "complejo" en trminos de uno ms "simple" y tener un caso "trivial" (no recursivo) que pueda resolverse de manera directa. Al hacerlo, puede desarrollarse una solucin si se supone que se ha resuelto el caso ms simple. La versin C de la funcin factorial supone que est definido (n 1)! y usa esa cantidad al calcular n!. Otra forma de aplicar estas ideas a otros ejemplos antes explicados. En la definicin de a * b, es trivial el caso de b = 1, pues a * b es igual a a. En general, a + b puede definirse en trminos de a * (b 1) mediante la definicin a * b = a * (b 1) + a. De nuevo, el caso complejo se transforma en un caso ms simple al restar 1, lo que lleva, al final, al caso trivial de b = 1. Aqu la recursin se basa nicamente en el segundo parmetro, b. Con respecto al ejemplo de la funcin de Fibonacci, se definieron dos casos triviales: fib(0) = 0 y fib(1) = 1. Un caso complejo fib(n) se reduce entonces a dos ms simples: fib(n 1) y fib(n 2). Esto se debe a la definicin de fib(n) como fib(n 1) + fib(n 2), donde se requiere de dos casos triviales definidos de manera directa. Fib(1) no puede definirse como fib(0) + fib(-1) porque la funcin de Fibonacci no est definida para nmeros negativos. 6.- Asignacin esttica y dinmica de memoria: Hasta este momento solamente hemos realizado asignaciones estticas del programa, y ms concretamente estas asignaciones estticas no eran otras que las declaraciones de variables en nuestro programa. Cuando declaramos una variable se reserva la memoria suficiente para contener la informacin que debe almacenar. Esta memoria permanece asignada a la variable hasta que termine la ejecucin del programa (funcin main). Realmente las variables locales de las funciones se crean cuando stas son llamadas pero nosotros no tenemos control sobre esa memoria, el compilador genera el cdigo para esta operacin automticamente. En este sentido las variables locales estn asociadas a asignaciones de memoria dinmicas, puesto que se crean y destruyen durante la ejecucin del programa. As entendemos por asignaciones de memoria dinmica, aquellas que son creadas por nuestro programa mientras se estn ejecutando y que por tanto, cuya gestin debe ser realizada por el programador. El lenguaje C dispone, como ya indicamos con anterioridad, de una serie de libreras de funciones estndar. El fichero de cabeceras stdlib.h contiene las declaraciones de dos funciones que nos permiten reservar memoria, as como otra funcin que nos permite liberarla. Las dos funciones que nos permiten reservar memoria son: malloc (cantidad_de_memoria); calloc (nmero_de_elementos, tamao_de_cada_elemento); Estas dos funciones reservan la memoria especificada y nos devuelven un puntero a la zona en cuestin. Si no se ha podido reservar el tamao de la memoria especificado devuelve un puntero con el valor 0 o NULL. El tipo del puntero es, en principio void, es decir, un puntero a cualquier cosa. Por tanto, a la hora de ejecutar estas funciones es aconsejable realizar una operacin cast (de conversin de tipo) de cara a la utilizacin de la aritmtica de punteros a la que aludamos anteriormente. Los compiladores modernos suelen realizar esta conversin automticamente. Antes de indicar como deben utilizarse las susodichas funciones tenemos que comentar el operador sizeof. Este operadores imprescindible a la hora de realizar programas portables, es decir, programas que puedan ejecutarse en cualquier mquina que disponga de un compilador de C. El operador sizeof (tipo_de_dato), nos devuelve el tamao que ocupa en memoria un cierto tipo de dato, de esta manera, podemos escribir programas independientes del tamao de los datos y de la longitud de palabra de la mquina. En resumen si no utilizamos este operador en conjuncin con las conversiones de tipo cast probablemente nuestro programa slo funciones en el ordenador sobre el que lo hemos programado. Por ejemplo, el los sistemas PC, la memoria est orientada a bytes y un entero ocupa 2 posiciones de memoria, sin embargo puede que en otro sistema la mquina est orientada a palabras (conjuntos de 2 bytes, aunque en general una mquina orientada a palabras tambin puede acceder a bytes) y por tanto el tamao de un entero sera de 1 posicin de memoria, suponiendo que ambas mquinas definan la misma precisin para este tipo.

Con todo lo mencionado anteriormente veamos un ejemplo de un programa que reserva dinmicamente memoria para algn dato. #include <stdlib.h if ((p_int==NULL)||(mat==NULL)) #include <stdio.h> { main() printf ("\nNo hay memoria"); { exit(1); int *p_int; } float *mat; /* Aqu iran las operaciones sobre los datos */ p_int = (int *) malloc(sizeof(int)); /* Aqu ira el cdigo que libera la memoria */ mat = (float *)calloc(20,sizeof(float)); } Este programa declara dos variables que son punteros a un entero y a un float. A estos punteros se le asigna una zona de memoria, para el primero se reserva memoria para almacenar una variable entera y en el segundo se crea una matriz de veinte elementos cada uno de ellos un float. Obsrvese el uso de los operadores cast para modificar el tipo del puntero devuelto por malloc y calloc, as como la utilizacin del operador sizeof. Como se puede observar no resulta rentable la declaracin de una variable simple (un entero, por ejemplo, como en el programa anterior) dinmicamente, en primer lugar porque aunque la variable slo se utilice en una pequea parte del programa, compensa tener menos memoria (2 bytes para un entero) que incluir todo el cdigo de llamada a malloc y comprobacin de que la asignacin fue correcta (esto seguro que ocupa ms de dos bytes). En segundo lugar tenemos que trabajar con un puntero con lo cual el programa ya aparece un poco ms engorroso puesto que para las lecturas y asignaciones de las variables tenemos que utilizar el operador *. Para termina un breve comentario sobre las funciones anteriormente descritas. Bsicamente da lo mismo utilizar malloc y calloc para reservar memoria es equivalente: mat = (float *)calloc (20,sizeof(float)); mat = (float *)malloc (20*sizeof(float)); La diferencia fundamental es que, a la hora de definir matrices dinmicas calloc es mucho ms claro y adems inicializa todos los elementos de la matriz a cero. Ntese tambin que puesto que las matrices se referencian como un puntero la asignacin dinmica de una matriz nos permite acceder a sus elementos con instrucciones de la forma: NOTA: En realidad existen algunas diferencias al trabajar sobre mquinas con alineamiento de palabras. mat[0] = 5; mat[2] = mat[1]*mat[6]/67; Con lo cual el comentario sobre lo engorroso que resultaba trabajar con un puntero a una variable simple, en el caso de las matrices dinmicas no existe diferencia alguna con una declaracin normal de matrices. La funcin que nos permite liberar la memoria asignada con malloc y calloc es free(puntero), donde puntero es el puntero devuelto por malloc o calloc. En nuestro ejemplo anterior, podemos ahora escribir el cdigo etiquetado como: /* Ahora ira el cdigo que libera la memoria */ free (p_int); free(mat); Hay que tener cuidado a la hora de liberar la memoria. Tenemos que liberar todos los bloque que hemos asignado, con lo cual siempre debemos tener almacenados los punteros al principio de la zona que reservamos. Si mientras actuamos sobre los datos modificamos el valor del puntero al inicio de la zona reservada, la funcin free probablemente no podr liberar el bloque de memoria. 7.- Ejemplos: 7.1.- Las Torres de Hanoi: A continuacin se ver cmo pueden usarse tcnicas recursivas para lograr una solucin lgica y elegante de un problema que no se especifica en trminos recursivos. EL problema es el de "las torres de Hanoi", cuyo planteamiento inicial se muestra en la figura a continuacin...

Hay tres postes: A, B y C. En el poste A se ponen cinco discos de dimetro diferente de tal manera que un disco de dimetro mayor siempre queda debajo de uno de dimetro menor. El objetivo es mover los discos al poste C usando B como auxiliar. Slo puede moverse el disco superior de cualquier poste a otro poste, y un disco mayor jams puede quedar sobre uno menor. Considrese la posibilidad de encontrar una solucin. En efecto, ni siquiera es claro que exista una. Ahora se ver si se puede desarrollar una solucin. En lugar de concentrar la atencin en una solucin para cinco discos, considrese el caso general den discos. Supngase que se tiene una solucin para n 1 discos y que en trminos de sta, se pueda plantear la solucin para n 1 discos. El problema se resolvera entonces. Esto sucede porque en el caso trivial de un disco (al restar 1 de n de manera sucesiva se producir, al final, 1) la solucin es simple: slo hay que el nico disco del poste A a C. As se habr desarrollado una solucin recursiva si se plantea una solucin para n discos en trminos de n 1. Considrese la posibilidad de encontrar tal relacin. Para el caso de cinco discos en particular, supngase que se conoce la forma de mover cuatro de ellos del poste A al otro, de acuerdo con las reglas. Cmo puede completarse entonces el trabajo de mover el quinto disco? Cabe recordar que hay 3 postes disponibles. Supngase que se supo cmo mover cuatro discos del poste A al C. Entonces, se pondr mover stos exactamente igual hacia B usando el C como auxiliar. Esto da como resultado la situacin los cuatro primeros discos en el poste B, el mayor en A y en C ninguno. Entonces podr moverse el disco mayor de A a C y por ltimo aplicarse de nuevo la solucin recursiva para cuatro discos para moverlo de B a C, usando el poste A como auxilia. Por lo tanto, se puede establecer una solucin recursiva de las torres de Hanoi como sigue: Para mover n discos de A a C usando B como auxiliar: 1. Si n = = 1, mover el disco nico de A a C y parar. 2. Mover el disco superior de A a B n 1 veces, usando C como auxiliar. 3. Mover el disco restante de A a C. 4. Mover los disco n 1 de B a C usando A como auxiliar Con toda seguridad este algoritmo producir una solucin completa por cualquier valor de n. Si n = = , el paso 1 ser la solucin correcta. Si n = = 2, se sabe entonces que hay una solucin para n 1 = = 1, de manera tal que los pasos 2 y 4 se ejecutaran en forma correcta. De manera anloga, cuando n = = 3 ya se habr producido una solucin para n 1 = = 2, por lo que los pasos 2 y 4 pueden ser ejecutados. De esta forma se puede mostrar que la solucin funciona para n = = 1, 2, 3, 4, 5,... hasta el valor para el que se desee encontrar una solucin. Advirtase que la solucin se desarrollo mediante la identificacin de un caso trivial (n = = 1) y una solucin para el caso general y complejo (n) en trminos de un caso ms simple (n 1). Ya se demostr que las transformaciones sucesivas de una simulacin no recursivas de una rutina recursiva pueden conducir a un programa ms simple para resolver un problema. Ahora se simulara la recursin del problema y se intentara simplificar la simulacin no recursiva. towers (n, frompeg, topeg, auxpeg) /* mover los n 1 discos de arriba de A a B, usando int n; como auxiliar */ char auxpeg, frompeg, topeg; towers (n 1, frompeg, auxpeg, tpoeg); { /* move remaining disk from A to C */ /* si es solo un disco, mover y regresar */ printf ("/n%s%d%s%c%s%c%", "mover disco", n, "del if (n = = 1) { poste" frompeg, "al poste", topeg); printf (" /n%s%c%s%c%", "mover disco 1 del /* mover n 1 discos de B hacia C empleando a A poste",frompeg, "al poste", topeg); como auxiliar */ return; } /* fin del if*/ towers (n 1, auxpeg, topeg, frompeg);} /* fin de towers */ En esta funcin, hay cuatro parmetros, cada uno de los cuales est sujeto a cambios en cada llamada recursiva. En consecuencia, el rea de datos debe contener elementos que representen a los cuatro. No hay variables locales. Hay un solo valor temporal que se necesita para guardar el valor de n 1, pero esta se puede representar por un valor temporal similar en el programa de simulacin y no tiene que estar apilada.

Hay tres puntos posibles a los que regresa la funcin en varias llamadas: el programa de llamada y los dos puntos que siguen a las llamadas recursivas. Por lo tanto, se necesitan cuatro etiquetas. start: Label1: Label2: Label3: La direccin de regreso se codifica como un entero (1, 2 o 3) dentro de cada rea de datos. Considrese la siguiente simulacin no recursiva de towers: struct dataarea { switch (i) { int nparam; case 1: goto label1; char fromparam; case 2: goto label2; char toparam; case 3: goto label3; } /* fin del switch */ char auxparam; } /* fin del if */ short int retaddr; /* Esta es la primera llamada recursiva */ }; push (&s, &currarea); struct stack { -- currarea.nparam; int top struct dataarea item [MAXSTACK]; }; temp = currarea.auxparam; simtowers (m, frompeg, topeg, auxpeg) currarea.auxparam = currarea.toparam; int n; currarea.toparam = temp; char auspeg, frompeg, topeg; { currarea.retaddr = 2; struct stack s; got start; struct dataarea currarea; label2: /* se regresa a este punto desde la primera char temp; llamada recursiva */ short int i; printf ("/n%s%d%s%c%s%c", "mover disco", s.top = -1; currarea.nparam, "del poste", currarea.fromparam, currarea.nparam = 0; "al poste", currarea.toparam); currarea.fromparam = ; /* Esta es la segunda llamada recursiva */ currarea.toparam = ; push (&s, &currarea); currarea. auxparam = ; --currarea.nparam; currarea.retaddr = 0; temp = currarea.fromparam; /* colocar en la pila un rea de datos simulados */ currarea.fromparam = currarea.auxparam; push (&s, &currarea); currarea.auxparam = temp; /* asignar parmetros y direcciones de regreso del currarea.rtaddr = 3; rea de datos actual a sus valores apropiados */ got start; currarea.nparam = n; label3: /* se regresa a este punto desde la segunda currarea,fromparam = frompeg; llamada recursiva */ currarea,toparam = topeg; i = currarea.retaddr; currarea.auxparam = auxpeg; pop (&s, &currarea); currarea.retaddr = 1; swicth (i) { start: /* Este es el inicio de la rutina simulada */ case 1: goto label1; if (currarea.nparam = = 1) { case 2: goto label2; printf (" /n%s%c%s%c", "mover disco 1 del poste", case 3: goto label3; } /* fin del switch */ currarea.fromparam, "al poste", currarea.toparam) ; label1: return; i = currarea.retaddr; } /* fin de simtowers */ pop (&s, &currarea); Ahora se simplificar el programa. En primer lugar, debe observarse que se usan tres etiquetas para indicar direcciones de regreso; una para cada una de las dos llamadas recursivas y otra para el regreso al programa principal. Sin embargo, el regreso al programa principal puede sealarse por un subdesborde en la pila, de la misma for que en la segunda versin simfact. Esto deja dos etiquetas de regreso. Si pudiera eliminarse otra ms, sera innecesario guardar en la pila la direccin de regreso, ya que solo restara un punto al que se

podra transferir el control si se eliminan los elementos de la pila con xito. Ahora dirijamos nuestra atencin a la segunda llamada recursiva y a la instruccin: towers (n 1, auxpeg, topeg, frompeg); Las acciones que ocurren en la simulacin de esta llamada son las siguientes: 1. Se coloca el rea de datos vigente a 1 dentro de la pila. 2. En la nueva rea de datos vigente a 2, se asignan los valores respectivos n 1, auxpeg, topeg, y frompeg a los parmetros. 3. En el rea de datos vigente a 2, se fija la etiqueta de retorno a la direccin de la instruccin que sigue de inmediato a la llamada. 4. Se salta hacia el principio de la rutina simulada. 5. Despus de completar la rutina simulada, sta queda lista parar regresar. Las siguientes acciones se llevan a efecto: 6. Se salva la etiqueta de regreso, /, de rea de datos vigentes a 2. 7. Se eliminan de la pila y se fija el rea de datos vigente como el rea de datos eliminada de la pila, a 1. 8. Se transfiere el control a /. Sin embrago, / es la etiqueta del final del bloque del programa ya que la segunda llamada a towers aparece en la ltima instruccin de la funcin. Por lo tanto, el siguiente paso es volver a eliminar elementos de la pila y regresar. No se volver a hacer uso de la informacin del rea de datos vigente a 1, ya que sta es destruida en la eliminacin de los elementos en la pila tan pronto como se vuelve a almacenar. Puesto que no hay razn para volver a usar esta rea de datos, tampoco hay razn para salvarla en la pila durante la simulacin de la llamada. Los datos se deben salvar en la pila slo si se van a usar otra vez. En consecuencia, la seguida llamada a towers puede simularse en forma simple mediante: 1. El cambio de los parmetros en el rea de datos vigente a sus valores respectivos. 2. El "salto" al principio de la rutina simulada. Cuando la rutina simulada regresa puede hacerlo en forma directa a la rutina que llam a la versin vigente. No hay razn para ejecutar un regreso a la versin vigente, slo para regresar de inmediato a la versin previa. Por lo tanto, se elimina la necesidad de guardar en la pila la direccin de regreso al simular la llamada externa (ya que se puede sealar mediante subdesborde y simular la segunda llamada recursiva, ya que no hay necesidad de salvar y volver a almacenar al rea de datos de la rutina que llamada en este momento). La nica direccin de regreso que resta es la que sigue a la primera llamada recursiva. Ya que slo queda una direccin de regreso posible, no tiene caso guardarla en la pila para que se vuelva a insertar y eliminar con el resto de los datos. Siempre se eliminan elementos de la pila con xito, hay una solo direccin hacia la que se puede ejecutar un "salto" (la instruccin que sigue a la primera llamada). Como los nuevos valores de las variables del rea de datos vigente se obtendrn a partir de los datos antiguos de rea de datos vigente, es necesario declarar una variable adicional, temp, de manera que los valores sean intercambiables. 7.2.- El Problema de las Ocho Reinas: El problema de las ocho reinas y en general de las N reinas, se basa en colocar 8 reinas en un tablero de 8 8 (o N en un tablero de NxN, si el problema se generaliza), de forma que en no puede haber dos piezas en la misma lnea horizontal, vertical o diagonal, ver Figura 1. Para ver el grfico seleccione la opcin "Descargar" del men superior Figura 1: Posible solucin para el problema de las ocho reinas Este programa has sido muy estudiado por los matemticos. Se trata de un problema NP-Completo que no tiene solucin para N=2 y N=3. Para N=4 tiene una nica solucin. Para N=8 hay ms de 80 soluciones dependiendo de las restricciones que se impongan. Una forma de abordar el problema se lleva a cabo mediante la construccin de un predicado en Prolog del tipo siguiente: reinas (N, Solucin), donde N representa las dimensiones del tablero y el nmero de reinas y Solucin es una lista que contiene la permutacin de la lista de nmeros que resuelven el problema. Los ndices de dicha lista representan la columna en la que se encuentra una reina y el nmero que almacena la

posicin o ndice representa la fila donde la reina est colocada. As, para el ejemplo mostrado en la Figura 1, tenemos que R=[2,4,1,3]. Este problema es resuelto, de modo clsico, por el mtodo de prueba y error, luego se adapta perfectamente a un algoritmo de backtracking. Bsicamente, el problema se reduce a colocar una reina, e intentar repetir el proceso teniendo en cuenta la reina colocada. Si logramos poner todas las reinas el problema se ha resuelto, en caso contrario, deshacemos lo que llevamos hasta ahora y probamos con otra combinacin. Por tanto, hemos de generar un conjunto de permutaciones y seleccionar aquella que cumpla los requisitos impuestos por el juego. Veamos el cdigo que resuelve el problema: rango(N, N, [N]). atacada(X,Y):-atacada(X,1,Y). rango(N, M, [N|Cola]):-N<M, Aux is N+1, rango(Aux, atacada(X,N,[Y|Ys]):-X is Y+N; X is Y-N. M, Cola). atacada(X,N,[Y|Ys]):-N1 is N+1, atacada(X,N1,Ys). dame(X,[X|Xs],Xs). correcta([]). dame(X,[Y|Ys],[Y|Zs]):-dame(X,Ys,Zs). correcta([X|Y]):-correcta(Y), not atacada(X,Y). permuta([],[]). reina(N, Solucion):-rango(1,N,L1), permuta(L,[Z|Zs]):-dame(Z,L,Ys), permuta(Ys,Zs). permuta(L1,Solucion), correcta(Solucion). Es muy importante comprender como funciona cada uno de los predicados para entender el funcionamiento del algoritmo general. Prolog permite implementar los programas casi directamente a partir de las especificaciones realizadas a partir de un anlisis y diseo de la solucin desde un alto nivel de abstraccin. Adems el procedimiento de backtracking est implcito en el propio motor de inferencia, luego este paradigma se adapta perfectamente a nuestro problema. Si analizamos y diseamos nuestro problema tenemos que la forma de resolverlo se resume en los pasos siguientes: Para N, obtenemos una lista de nmeros comprendidos entre 1 y N: [1,2,3,4,...,N]. Obtenemos una permutacin del conjunto de nmeros de la lista. Comprobamos que la permutacin es correcta. Si la permutacin no es correcta, lo que debemos hacer es volver al paso 2 para generar una permutacin nueva. Comencemos a analizar la solucin implementada. El problema se resuelve con el predicado reina(N, Solucin): rango(1,N,L1), permuta(L1,Solucion), correcta Solucin).Como vemos es, sencillamente, una copia de las especificaciones realizadas ms arriba. Se genera el rango entre 1 y N, se obtiene una permutacin y se comprueba si la permutacin es, o no, correcta. En el caso de que cualquier predicado del consecuente falle, la propia mquina Prolog se encarga de realizar el proceso de backtracking. Con lo cual ya tenemos cubiertos los cuatro pasos fundamentales del algoritmo. Para tener ms claras las ideas, observemos el rbol de ejecucin general del objetivo reina(4,Solucion) en la Figura 2.

Figura 2: rbol de ejecucin para el objetivo reina (4, Solucion) He aqu otro ejemplo sobre el problema de las ocho reinas. Primero se mostrara un pseudocodigo sobre el mismo y luego su respectiva codificacin en el lenguaje C. <PRINCIPIO ensayar> (i: entero) | | | +-SI no acertado ENTONCES inicializar el conjunto de posiciones de la reina i| | | | quitar reina sima | | | +-FINSI +-REPETIR hacer la seleccin siguiente | | +-FINSI | +-SI segura ENTONCES | +-FINSI | | poner reina +-HASTA acertada O no hay ms posiciones | | +-SI i < 8 ENTONCES <FIN> | | | LLAMAR ensayar (i + 1) Observaciones sobre el cdigo: 1) Estudiar la funcin ensayar() a partir de este pseudocdigo. 2) Vectores utilizados: int posiciones_en_columna[8]; RANGO: 1..8 #define dn(i) reina_en_diagonal_normal[(i)+7] BOOLEAN reina_en_fila[8]; RANGO: 1..8 #define di(i) reina_en_diagonal_inversa[(i)-2] BOOLEAN reina_en_diagonal_normal[15]; RANGO: Significado de los vectores: 7..7 c(i) : la posicin de la reina en la columna i BOOLEAN reina_en_diagonal_inversa[15]; RANGO: f(j) : indicativo de que no hay reina en la fila j-sima 2..16 dn(k): indicativo de que no hay reina en la diagonal En C, el primer elemento de cada vector tiene ndice normal 0, esto (\) k-sima es fcil solucionarlo con las siguientes macros: di(k): indicativo de que no hay reina en la diagonal #define c(i) posiciones_en_columna[(i)-1] invertida (/) k-sima #define f(i) reina_en_fila[(i)-1] Dado que se sabe, por las reglas del ajedrez, que una reina acta sobre todas las piezas situadas en la misma columna, fila o diagonal del tablero se deduce que cada columna puede contener una y slo una reina, y que la eleccin de la situacin de la reina i-sima puede restringirse a los cuadros de la columna i. Por tanto, el parmetro i se convierte en el ndice de columna, y por ello el proceso de seleccin de posiciones queda limitado a los ocho posibles valores del ndice de fila j. A partir de estos datos, la lnea poner reina del pseudocdigo es: c (i) = j; f (j) = di (i + j) = dn (i - j) = FALSE; #define c(i) posiciones_en_columna[(i)-1] y la lnea quitar reina del pseudocdigo: /* rango de ndice: 1..8 */ f (j) = di (i + j) = dn (i - j) = TRUE; #define f(i) reina_en_fila[(i)-1] y la condicin segura del pseudocdigo: /* rango de ndice: 1..8 */ f (i) && di (i + j) && dn (i - j) #define dn(i) reina_en_diagonal_normal[(i)+7] /* Ficheros a incluir: */ /* rango de ndice: -7..7 */ #include <stdio.h> /* printf () */ #define di(i) reina_en_diagonal_inversa[(i)-2] #include <conio.h> /* getch () */ /* rango de ndice: 2..16 */ /* Macros: */ /* Prototipos de las funciones: */ #define BOOLEAN int void proceso (void); #define TRUE 1 void ensayar (int i); #define FALSE 0 /* Definiciones de las funciones: */ /* Variables globales: */ void main (void) BOOLEAN acertado; { int posiciones_en_columna[8]; printf ("\n\nPROBLEMA DE LAS OCHO REINAS:\n BOOLEAN reina_en_fila[8]; "); BOOLEAN reina_en_diagonal_normal[15]; proceso (); BOOLEAN reina_en_diagonal_inversa[15]; printf ("\n\nPulsa cualquier tecla para finalizar. ");

getch (); void ensayar (int i) } { void proceso (void) int j = 0; { do register int i,j; { for (i = 1; i <= 8; i++) j++; f (i) = TRUE; acertado = FALSE; for (i = 2; i <= 16; i++) if (f (j) && di (i + j) && dn (i - j)) di (i) = TRUE; { for (i = -7; i <= 7; i++) c (i) = j; dn (i) = TRUE; f (j) = di (i + j) = dn (i - j) = FALSE; ensayar (1); if (i < 8) if (acertado) { for (printf ("\n\nLA SOLUCION ES:\n\n"), i = 1; i <= ensayar (i + 1); 8; i++) if (! acertado) { f (j) = di (i + j) = dn (i - j) = TRUE; for (j = 1; j <= 8; j++) } printf ("%2d", c (j) == i ? 1 : 0); else printf ("\n"); acertado = TRUE; } } else } while (! acertado && j != 8); printf ("\n\nNO HAY SOLUCION.\n"); } } CONCLUSIN Se puede decir que la recursividad es una tcnica de programacin bastante til y muy interesante de estudiar. A travs de los ejemplos que el individuopueda revisar, aprender con ms rapidez y sencillez lo que es programar recursivamente e incluir esta tcnica cuando se le presente un problema como los que fueron mencionados anteriormente. La asignacin de memoria, sea esttica o dinmica, en realidad se tendr que aplicar en cualquier programa al momento de su codificacin; tomando en cuenta que cada programador tiene su estilo de programar. El ejemplo de las torres de Hanoi tanto como el ejemplo de las ocho reinas son problemas claves que tienen que ver directamente con lo que es la recursividad. Tipos de programacin Existen varias clases de programacin, dependiendo de los mtodos utilizados y las tcnicas empleadas. Los tipos o tcnicas de programacin son bastante variados, aunque puede que muchos de los lectores slo conozcan una metodologa para realizar programas. En la mayora de los casos, las tcnicas se centran en programacin modular y programacin estructurada, pero existen otros tipos de programacin. Los explicaremos a lo largo del artculo. Programacin estructurada (PE): La programacin estructurada est compuesta por un conjunto de tcnicas que han ido evolucionando aumentando considerablemente la productividad del programa reduciendo el tiempo de depuracin y mantenimiento del mismo. Esta programacin estructurada utiliza un nmero limitado de estructuras de control, reduciendo as considerablemente los errores. Esta tcnica incorpora: Diseo descendente (top-dow): el problema se descompone en etapas o estructuras jerrquicas. Recursos abstractos (simplicidad): consiste en descompones las acciones complejas en otras ms simples capaces de ser resueltas con mayor facilidad. Estructuras bsicas: existen tres tipos de estructuras bsicas:

Estructuras secunciales: cada accin sigue a otra accin secuencialmente. La salida de una accin es la entrada de otra. o Estructuras selectivas: en estas estructuras se evalan las condiciones y en funcin del resultado de las mismas se realizan unas acciones u otras. Se utilizan expresiones lgicas. o Estructuras repetitivas: son secuencias de instrucciones que se repiten un nmero determinado de veces. Las principales ventajas de la programacin estructurada son: Los programas son ms fciles de entender Se reduce la complejidad de las pruebas Aumenta la productividad del programador Los programas queden mejor documentados internamente. Un programa est estructurado si posee un nico punto de entrada y slo uno de salida, existen de "1 a n" caminos desde el principio hasta el fin del programa y por ltimo, que todas las instrucciones son ejecutables sin que aparezcan bucles infinitos. Programacin modular: En la programacin modular consta de varias secciones dividas de forma que interactan a travs de llamadas a procedimientos, que integran el programa en su totalidad. En la programacin modular, el programa principal coordina las llamadas a los mdulos secundarios y pasa los datos necesarios en forma de parmetros. A su vez cada mdulo puede contener sus propios datos y llamar a otros mdulos o funciones. Programacin orientada a objetos (POO) : Se trata de una tcnica que aumenta considerablemente la velocidad de desarrollo de los programas gracias a la reutilizacin de los objetos. El elemento principal de la programacin orientada a objetos es el objeto. El objeto es un conjunto complejo de datos y programas que poseen estructura y forman parte de una organizacin. Un objeto contiene varios datos bien estructurados y pueden ser visibles o no dependiendo del programador y las acciones del programa en ese momento. El polimorfismo y la herencia son unas de sus principales caractersticas y por ello dedicaremos ms adelante un artculo exclusivamente a tratar estos dos trminos. Programacin concurrente: Este tipo de programacin se utiliza cuando tenemos que realizar varias acciones a la vez. Se suele utilizar para controlar los accesos de usuarios y programas a un recurso de forma simultnea. Se trata de una programacin ms lenta y laboriosa, obteniendo unos resultados lentos en las acciones. Programacin funcional: Se caracteriza principalmente por permitir declarar y llamar a funciones dentro de otras funciones. Programacin lgica: Se suele utilizar en la inteligencia artificial y pequeos programas infantiles. Se trata de una programacin basada en el clculo de predicados (una teora matemtica que permite lograr que un ordenador basndose en hecho y reglas lgicas, pueda dar soluciones inteligentes). Programacin estructurada La programacin estructurada es una tcnica para escribir programas (programacin de computadora). Para ello se utilizan nicamente tres estructuras: secuencia, seleccin e iteracin; siendo innecesario el uso de la instruccin o instrucciones de transferencia incondicional (GOTO, EXIT FUNCTION, EXIT SUB o mltiples RETURN). Hoy en da las aplicaciones informticas son mucho ms ambiciosas que las necesidades de programacin existentes en los aos 1960, principalmente debido a las aplicaciones grficas, por lo que las tcnicas de programacin estructurada no son suficientes. Ello ha llevado al desarrollo de nuevas tcnicas, tales como la programacin orientada a objetos y el desarrollo de entornos de programacin que facilitan la programacin de grandes aplicaciones.

Orgenes de la programacin estructurada A finales de los aos 1970 surgi una nueva forma de programar que no solamente daba lugar a programas fiables y eficientes, sino que adems estaban escritos de manera que facilitaba su comprensin posterior. El teorema del programa estructurado, propuesto por Bhm-Jacopini, demuestra que todo programa puede escribirse utilizando nicamente las tres instrucciones de control siguientes: Secuencia Instruccin condicional. Iteracin (bucle de instrucciones) con condicin al principio. Solamente con estas tres estructuras se pueden escribir todos los programas y aplicaciones posibles. Si bien los lenguajes de programacin tienen un mayor repertorio de estructuras de control, stas pueden ser construidas mediante las tres bsicas citadas. Estructura secuencial: Una estructura de programa es secuencial si las instrucciones se ejecutan una tras otra, a modo de secuencia lineal, es decir que una instruccin no se ejecuta hasta que finaliza la anterior, ni se bifurca el flujo del programa. Ejemplo: INPUT x auxiliar= x y= auxiliar PRINT y INPUT y x= y PRINT x Esta secuencia de instrucciones permuta los valores de x e y, con ayuda de una variable auxiliar, intermedia. 1 Se guarda una copia del valor de x en auxiliar. 2 Se guarda el valor de y en x, perdiendo su valor anterior, pero se mantiene una copia del contenido en auxiliar. 3 Se copia a y el valor de auxiliar, que es el valor inicial de x. El resultado es el intercambio de los valores entre x e y, en tres operaciones secuenciales. Estructura selectiva o de seleccin: La estructura selectiva permite que la ejecucin del programa se bifurque a una instruccin (o conjunto) u otra/s, segn un criterio o condicin lgica establecida, slo uno de los caminos en la bifurcacin ser el tomado para ejecutarse. Ejemplo: IF a > b THEN PRINT a ; " no es mayor que " ; b PRINT a ; " es mayor que " ; b END IF ELSE La instruccin selectiva anterior puede presentar uno de dos mensajes: a es mayor que b o a no es mayor que b, segn el resultado de la comparacin entre a y b; si el resultado de a > b es verdadero, se presenta el primer mensaje, si es falso se exterioriza el segundo. Las palabras clave IF, THEN, ELSE, y END IF; constituyen la propia estructura de la instruccin condicional (palabra reservadas), proporcionada por el lenguaje, el usuario no debe utilizar sus nombres salvo para este fin. El caso ejemplo se ha codificado en BASIC. IF seala el comienzo de la instruccin condicional, y se espera que despus siga la condicin lgica de control de la instruccin. THEN seala el fin de la condicin, y despus estar la instruccin a ejecutar si la condicin es verdadera. ELSE es opcional, le sigue la instruccin que se ejecutar si la condicin es falsa. END IF indica el final de la estructura, luego de sta el programa seguir su curso. Ampliando un poco el ejemplo anterior, con estructuras anidadas: IF a > b THEN ELSE PRINT a ; " es mayor que " ; b PRINT a ; " es igual que " ; b ELSEIF a < b THEN END IF PRINT a ; " es menor que " ; b Este ejemplo permite considerar situaciones en las que se tiene ms de dos alternativas. En este caso se ha considerado tres, pero hay situaciones en las que deben considerarse ms casos y para ellos se puede repetir las veces que sea necesario la opcional ELSEIF.

Estructura iterativa: Un bucle iterativo o iteracin de una secuencia de instrucciones, hace que se repita su ejecucin mientras se cumpla una condicin, el nmero de iteraciones normalmente est determinado por el cambio en la condicin dentro del mismo bucle, aunque puede ser forzado o explcito por otra condicin. Ejemplo: a= 0 DO WHILE b > a a= a + 1 b= 7 PRINT a LOOP Esta instruccin tiene tres palabras reservadas WHILE, DO y LOOP. DO WHILE: seala el comienzo del bucle ("haga mientras") y despus de estas palabras se espera la condicin lgica de repeticin, si la condicin es verdadera pasa el control al cuerpo del bucle, en caso contrario el flujo salta directamente al final de la estructura, saliendo de la misma. LOOP: seala el final del cuerpo de la estructura de bucle. El bucle mientras, se repite mientras la condicin sea verdadera, esta condicin se comprueba o chequea antes de ingresar al cuerpo del bucle, por lo que el mismo puede que no se ejecute nunca (cuando la condicin es falsa desde un principio) o bien que se repita tantas veces como resulte y mientras la condicin sea cierta. En el ejemplo se tienen definidas dos variables a y b, que al iniciarse el bucle contienen los valores a=0 y b=7. La condicin del bucle es b > a. Si a=0 y b=7. la condicin es verdadera, en el cuerpo del bucle se escribe el valor de a en pantalla y luego se incrementa esa variable en una unidad. Entonces pasa a ser a=1 y b=7. ... (se repite la secuencia) ... Cuando a=6 y b=7. la condicin sigue siendo verdadera, se escribe el valor de a en pantalla y se incrementa en una unidad. Cuando se llega a que a=7 y b=7. Entonces la condicin ya resulta falsa y la instruccin WHILE finaliza, saliendo por LOOP. La salida por pantalla de este ejemplo es 0 1 2 3 4 5 6, y se iter 7 veces. El lenguaje utilizado en el ejemplo (BASIC), adems de tener otras del tipo iterativas, permite utilizar la misma estructura indicada, pero de la siguiente forma: a= 0 WHILE b > a a= a + 1 b= 7 PRINT a WEND Que es absolutamente anloga, en ste formato la palabra reservada WEND marca el fin del bucle y no se utiliza ni DO ni LOOP. Anidamiento: El cuerpo de cualquier estructura puede ser instrucciones simples u otras estructuras, que a su vez pueden contener a otras. Ejemplo: CLS DO WHILE auxiliar > a INPUT "Valor entero para a:"; a auxiliar = auxiliar - 1 INPUT "Valor entero para b:"; b PRINT auxiliar IF a > b THEN LOOP REM hacer intercambio de variables ELSE auxiliar = a REM no hacer nada a=b END IF b = auxiliar PRINT REM imprimir diferencia en escala de uno en uno PRINT a; b En el ejemplo la sentencia o instruccin CLS slo tiene el efecto de "limpiar" la pantalla al inicio de la ejecucin del programa. Las instrucciones INPUT permiten que el operador ingrese, desde teclado y con un mensaje previo acorde, los valores deseados para las variables a y b. La instruccin no ejecutable REM permite la insercin de comentarios en cualquier parte del programa, donde el programador lo considere necesario; constituye una buena prctica de programacin comentar adecuadamente todos los programas,

de este modo se clarifica notablemente su lectura, durante su desarrollo y posterior para modificacin o mantenimiento. En la anterior estructura IF bien se puede omitir la porcin ELSE, ya que no hay cuerpo all, de modo que lo siguiente es completamente equivalente: CLS REM imprimir diferencia en escala de uno en uno INPUT "Valor entero para a:"; a DO WHILE auxiliar > a INPUT "Valor entero para b:"; b auxiliar = auxiliar - 1 IF a > b THEN PRINT auxiliar REM hacer intercambio de variables LOOP auxiliar = a END IF a=b PRINT b = auxiliar PRINT a; b Caractersticas de la programacin estructurada 1. Los programas son ms fciles de entender, pueden ser ledos de forma secuencial, no hay necesidad de hacer engorrosos seguimientos en saltos de lnea (GOTO) dentro de los bloques de cdigo para intentar entender la lgica. 2. La estructura de los programas es clara, puesto que las instrucciones estn ms ligadas o relacionadas entre s. 3. Reduccin del esfuerzo en las pruebas y depuracin. El seguimiento de los fallos o errores del programa ("debugging") se facilita debido a su estructura ms sencilla y comprensible, por lo que los errores se pueden detectar y corregir ms fcilmente. 4. Reduccin de los costos de mantenimiento. Anlogamente a la depuracin, durante la fase de mantenimiento, modificar o extender los programas resulta ms fcil. 5. Programas son ms sencillos y ms rpidos de confeccionar (y se facilita su optimizacin). 6. Los bloques de cdigo son casi auto-explicativos, lo que reduce y facilita la documentacin. 7. Las instrucciones de salto, GOTO, quedan reservadas para construir las instrucciones bsicas, si fuera realmente imprescindible. Aunque no se usan de forma directa, por estar prohibida su utilizacin, estn incluidas implcitamente en las instrucciones de seleccin e iteracin. 8. Un programa escrito de acuerdo a los principios de programacin estructurada no solamente tendr una mejor estructura sino tambin una excelente presentacin. 9. Se incrementa el rendimiento de los programadores, comparada con la forma tradicional que utiliza GOTO. La programacin estructurada ofrece estos beneficios, pero no se la debe considerar como una panacea ya que el desarrollo de programas es, esencialmente, una tarea de dedicacin, esfuerzo y creatividad; programar es casi un arte. Inconvenientes de la programacin estructurada El principal inconveniente de este mtodo de programacin es que se obtiene un nico bloque de programa, que cuando se hace demasiado grande puede resultar problemtico el manejo de su cdigo fuente; esto se resuelve empleando conjuntamente la programacin modular, es decir, si es necesario, se definen mdulos independientes, programados y compilados por separado (en realidad esto no es necesario, pero s es recomendable para su mejor mantenimiento y depuracin). En realidad, cuando se programa hoy en da (inicios del siglo XXI) se utilizan normalmente, tanto las tcnicas de programacin estructurada como las de programacin modular, de forma conjunta y por lo tanto es muy comn que cuando se hace referencia a la programacin estructurada muchos entiendan que ella incluye tambin las tcnicas modulares, estrictamente no es as. Un mtodo un poco ms sofisticado es la programacin por capas, en la que los mdulos tienen una estructura jerrquica en la que se pueden definir funciones dentro de funciones o de procedimientos.

Si bien las metodologas en cuestin ya son de antigua data ("en plazos informticos"), aun en la actualidad la conjuncin "Programacin estructurada" y "programacin modular" es una de la ms utilizadas, juntamente con un ms moderno paradigma, en pleno auge, completamente distinto, llamado programacin orientada a objetos. Programacin modular Diagrama del funcionamiento de un subprograma. La programacin modular es un paradigma de programacin que consiste en dividir un programa en mdulos o subprogramas con el fin de hacerlo ms legible y manejable. Se presenta histricamente como una evolucin de la programacin estructurada para solucionar problemas de programacin ms grandes y complejos de lo que sta puede resolver. Al aplicar la programacin modular, un problema complejo debe ser dividido en varios subproblemas ms simples, y estos a su vez en otros subproblemas ms simples. Esto debe hacerse hasta obtener subproblemas lo suficientemente simples como para poder ser resueltos fcilmente con algn lenguaje de programacin. sta tcnica se llama refinamiento sucesivo, divide y vencers anlisis descendente (Top-Down). Un mdulo es cada una de las partes de un programa que resuelve uno de los subproblemas en que se divide el problema complejo original. Cada uno de estos mdulos tiene una tarea bien definida y algunos necesitan de otros para poder operar. En caso de que un mdulo necesite de otro, puede comunicarse con ste mediante una interfaz de comunicacin que tambin debe estar bien definida. Si bien un mdulo puede entenderse como una parte de un programa en cualquiera de sus formas y variados contextos, en la prctica se los suele tomar como sinnimos de procedimientos y funciones. Pero no necesaria ni estrictamente un mdulo es una funcin o un procedimiento, ya que el mismo puede contener muchos de ellos, no debe confundirse el trmino "modulo" (en el sentido de programacin modular) con trminos como "funcin" o "procedimiento", propios del lenguaje que lo soporte. Programacin orientada a objetos La programacin orientada a objetos o POO (OOP segn sus siglas en ingls) es un paradigma de programacin que usa los objetos en sus interacciones, para disear aplicaciones y programas informticos. Est basado en varias tcnicas, incluyendo herencia, abstraccin, polimorfismo y encapsulamiento. Su uso se populariz a principios de la dcada de los aos 1990. En la actualidad, existe variedad de lenguajes de programacin que soportan la orientacin a objetos. Introduccin Los objetos son entidades que tienen un determinado estado, comportamiento (mtodo) e identidad: El estado est compuesto de datos o informaciones, ser uno o varios atributos a los que se habrn asignado unos valores concretos (datos). El comportamiento est definido por los mtodos o mensajes a los que sabe responder dicho objeto, es decir, qu operaciones se pueden realizar con l. La identidad es una propiedad de un objeto que lo diferencia del resto, dicho con otras palabras, es su identificador (concepto anlogo al de identificador de una variable o una constante). Un objeto contiene toda la informacin que permite definirlo e identificarlo frente a otros objetos pertenecientes a otras clases e incluso frente a objetos de una misma clase, al poder tener valores bien diferenciados en sus atributos. A su vez, los objetos disponen de mecanismos de interaccin llamados mtodos, que favorecen la comunicacin entre ellos. Esta comunicacin favorece a su vez el cambio de estado en los propios objetos. Esta caracterstica lleva a tratarlos como unidades indivisibles, en las que no se separa el estado y el comportamiento.

Los mtodos (comportamiento) y atributos (estado) estn estrechamente relacionados por la propiedad de conjunto. Esta propiedad destaca que una clase requiere de mtodos para poder tratar los atributos con los que cuenta. El programador debe pensar indistintamente en ambos conceptos, sin separar ni darle mayor importancia a alguno de ellos. Hacerlo podra producir el hbito errneo de crear clases contenedoras de informacin por un lado y clases con mtodos que manejen a las primeras por el otro. De esta manera se estara realizando una programacin estructurada camuflada en un lenguaje de programacin orientado a objetos. La POO difiere de la programacin estructurada tradicional, en la que los datos y los procedimientos estn separados y sin relacin, ya que lo nico que se busca es el procesamiento de unos datos de entrada para obtener otros de salida. La programacin estructurada anima al programador a pensar sobre todo en trminos de procedimientos o funciones, y en segundo lugar en las estructuras de datos que esos procedimientos manejan. En la programacin estructurada solo se escriben funciones que procesan datos. Los programadores que emplean POO, en cambio, primero definen objetos para luego enviarles mensajes solicitndoles que realicen sus mtodos por s mismos. Origen Los conceptos de la programacin orientada a objetos tienen origen en Simula 67, un lenguaje diseado para hacer simulaciones, creado por Ole-Johan Dahl y Kristen Nygaard del Centro de Cmputo Noruego en Oslo. En este centro, se trabajaba en simulaciones de naves, que fueron confundidas por la explosin combinatoria de cmo las diversas cualidades de diferentes naves podan afectar unas a las otras. La idea surgi al agrupar los diversos tipos de naves en diversas clases de objetos, siendo responsable cada clase de objetos de definir sus propios datos y comportamientos. Fueron refinados ms tarde en Smalltalk, desarrollado en Simula en Xerox PARC (cuya primera versin fue escrita sobre Basic) pero diseado para ser un sistema completamente dinmico en el cual los objetos se podran crear y modificar "sobre la marcha" (en tiempo de ejecucin) en lugar de tener un sistema basado en programas estticos. La programacin orientada a objetos se fue convirtiendo en el estilo de programacin dominante a mediados de los aos ochenta, en gran parte debido a la influencia de C++, una extensin dellenguaje de programacin C. Su dominacin fue consolidada gracias al auge de las Interfaces grficas de usuario, para las cuales la programacin orientada a objetos est particularmente bien adaptada. En este caso, se habla tambin de programacin dirigida por eventos. Las caractersticas de orientacin a objetos fueron agregadas a muchos lenguajes existentes durante ese tiempo, incluyendo Ada, BASIC, Lisp, Pascal, entre otros. La adicin de estas caractersticas a los lenguajes que no fueron diseados inicialmente para ellas condujo a menudo a problemas de compatibilidad y en la capacidad de mantenimiento del cdigo. Los lenguajes orientados a objetos "puros", por su parte, carecan de las caractersticas de las cuales muchos programadores haban venido a depender. Para saltar este obstculo, se hicieron muchas tentativas para crear nuevos lenguajes basados en mtodos orientados a objetos, pero permitiendo algunas caractersticas imperativas de maneras "seguras". El Eiffel de Bertrand Meyer fue un temprano y moderadamente acertado lenguaje con esos objetivos pero ahora ha sido esencialmente reemplazado por Java, en gran parte debido a la aparicin de Internet, y a la implementacin de la mquina virtual de Java en la mayora de navegadores. PHP en su versin 5 se ha modificado, soporta una orientacin completa a objetos, cumpliendo todas las caractersticas propias de la orientacin a objetos. Conceptos fundamentales La programacin orientada a objetos es una forma de programar que trata de encontrar una solucin a estos problemas. Introduce nuevos conceptos, que superan y amplan conceptos antiguos ya conocidos. Entre ellos destacan los siguientes: Clase: definiciones de las propiedades y comportamiento de un tipo de objeto concreto. La instanciacin es la lectura de estas definiciones y la creacin de un objeto a partir de ellas.

Herencia: (por ejemplo, herencia de la clase C a la clase D) Es la facilidad mediante la cual la clase D hereda

en ella cada uno de los atributos y operaciones de C, como si esos atributos y operaciones hubiesen sido definidos por la misma D. Por lo tanto, puede usar los mismos mtodos y variables pblicas declaradas en C. Los componentes registrados como "privados" (private) tambin se heredan, pero como no pertenecen a la clase, se mantienen escondidos al programador y slo pueden ser accedidos a travs de otros mtodos pblicos. Esto es as para mantener hegemnico el ideal de OOP. Objeto: entidad provista de un conjunto de propiedades o atributos (datos) y de comportamiento o funcionalidad (mtodos) los mismos que consecuentemente reaccionan a eventos. Se corresponde con los objetos reales del mundo que nos rodea, o a objetos internos del sistema (del programa). Es una instancia a una clase. Mtodo: Algoritmo asociado a un objeto (o a una clase de objetos), cuya ejecucin se desencadena tras la recepcin de un "mensaje". Desde el punto de vista del comportamiento, es lo que el objeto puede hacer. Un mtodo puede producir un cambio en las propiedades del objeto, o la generacin de un "evento" con un nuevo mensaje para otro objeto del sistema. Evento: Es un suceso en el sistema (tal como una interaccin del usuario con la mquina, o un mensaje enviado por un objeto). El sistema maneja el evento enviando el mensaje adecuado al objeto pertinente. Tambin se puede definir como evento, a la reaccin que puede desencadenar un objeto, es decir la accin que genera. Mensaje: una comunicacin dirigida a un objeto, que le ordena que ejecute uno de sus mtodos con ciertos parmetros asociados al evento que lo gener. Propiedad o atributo: contenedor de un tipo de datos asociados a un objeto (o a una clase de objetos), que hace los datos visibles desde fuera del objeto y esto se define como sus caractersticas predeterminadas, y cuyo valor puede ser alterado por la ejecucin de algn mtodo. Estado interno: es una variable que se declara privada, que puede ser nicamente accedida y alterada por un mtodo del objeto, y que se utiliza para indicar distintas situaciones posibles para el objeto (o clase de objetos). No es visible al programador que maneja una instancia de la clase. Componentes de un objeto: atributos, identidad, relaciones y mtodos. Identificacin de un objeto: un objeto se representa por medio de una tabla o entidad que est compuesta por sus atributos y funciones correspondientes. En comparacin con un lenguaje imperativo, una "variable", no es ms que un contenedor interno del atributo del objeto o de un estado interno, as como la "funcin" es un procedimiento interno del mtodo del objeto. Caractersticas de la POO Existe un acuerdo acerca de qu caractersticas contempla la "orientacin a objetos", las caractersticas siguientes son las ms importantes: Abstraccin: denota las caractersticas esenciales de un objeto, donde se capturan sus comportamientos. Cada objeto en el sistema sirve como modelo de un "agente" abstracto que puede realizar trabajo, informar y cambiar su estado, y "comunicarse" con otros objetos en el sistema sin revelar cmo se implementan estas caractersticas. Los procesos, las funciones o los mtodos pueden tambin ser abstrados y cuando lo estn, una variedad de tcnicas son requeridas para ampliar una abstraccin. El proceso de abstraccin permite seleccionar las caractersticas relevantes dentro de un conjunto e identificar comportamientos comunes para definir nuevos tipos de entidades en el mundo real. La abstraccin es clave en el proceso de anlisis y diseo orientado a objetos, ya que mediante ella podemos llegar a armar un conjunto de clases que permitan modelar la realidad o el problema que se quiere atacar. Encapsulamiento: Significa reunir a todos los elementos que pueden considerarse pertenecientes a una misma entidad, al mismo nivel de abstraccin. Esto permite aumentar la cohesin de los componentes del sistema. Algunos autores confunden este concepto con el principio de ocultacin, principalmente porque se suelen emplear conjuntamente.

Modularidad: Se denomina Modularidad a la propiedad que permite subdividir una aplicacin en partes ms pequeas (llamadas mdulos), cada una de las cuales debe ser tan independiente como sea posible de la aplicacin en s y de las restantes partes. Estos mdulos se pueden compilar por separado, pero tienen conexiones con otros mdulos. Al igual que la encapsulacin, los lenguajes soportan la Modularidad de diversas formas. Principio de ocultacin: Cada objeto est aislado del exterior, es un mdulo natural, y cada tipo de objeto expone una interfaz a otros objetos que especifica cmo pueden interactuar con los objetos de la clase. El aislamiento protege a las propiedades de un objeto contra su modificacin por quien no tenga derecho a acceder a ellas, solamente los propios mtodos internos del objeto pueden acceder a su estado. Esto asegura que otros objetos no pueden cambiar el estado interno de un objeto de maneras inesperadas, eliminando efectos secundarios e interacciones inesperadas. Algunos lenguajes relajan esto, permitiendo un acceso directo a los datos internos del objeto de una manera controlada y limitando el grado de abstraccin. La aplicacin entera se reduce a un agregado o rompecabezas de objetos. Polimorfismo: comportamientos diferentes, asociados a objetos distintos, pueden compartir el mismo nombre, al llamarlos por ese nombre se utilizar el comportamiento correspondiente al objeto que se est usando. O dicho de otro modo, las referencias y las colecciones de objetos pueden contener objetos de diferentes tipos, y la invocacin de un comportamiento en una referencia producir el comportamiento correcto para el tipo real del objeto referenciado. Cuando esto ocurre en "tiempo de ejecucin", esta ltima caracterstica se llama asignacin tarda oasignacin dinmica. Algunos lenguajes proporcionan medios ms estticos (en "tiempo de compilacin") de polimorfismo, tales como las plantillas y la sobrecarga de operadores de C++. Herencia: las clases no estn aisladas, sino que se relacionan entre s, formando una jerarqua de clasificacin. Los objetos heredan las propiedades y el comportamiento de todas las clases a las que pertenecen. La herencia organiza y facilita el polimorfismo y el encapsulamiento permitiendo a los objetos ser definidos y creados como tipos especializados de objetos preexistentes. Estos pueden compartir (y extender) su comportamiento sin tener que volver a implementarlo. Esto suele hacerse habitualmente agrupando los objetos en clases y estas enrboles o enrejados que reflejan un comportamiento comn. Cuando un objeto hereda de ms de una clase se dice que hay herencia mltiple. Recoleccin de basura: la recoleccin de basura o garbage collector es la tcnica por la cual el entorno de objetos se encarga de destruir automticamente, y por tanto desvincular la memoria asociada, los objetos que hayan quedado sin ninguna referencia a ellos. Esto significa que el programador no debe preocuparse por la asignacin o liberacin de memoria, ya que el entorno la asignar al crear un nuevo objeto y la liberar cuando nadie lo est usando. En la mayora de los lenguajes hbridos que se extendieron para soportar el Paradigma de Programacin Orientada a Objetos como C++ u Object Pascal, esta caracterstica no existe y la memoria debe desasignarse manualmente. Resumen La programacin orientada a objetos es un paradigma que utiliza objetos como elementos fundamentales en la construccin de la solucin. Surge en los aos 70. Un objeto es una abstraccin de algn hecho o ente del mundo real que tiene atributos que representan sus caractersticas o propiedades y mtodos que representan su comportamiento o acciones que realizan. Todas las propiedades y mtodos comunes a los objetos se encapsulan o se agrupan en clases. Una clase es una plantilla o un prototipo para crear objetos, por eso se dice que los objetos son instancias de clases. Lenguajes orientados a objetos Simula (1967) es aceptado como el primer lenguaje que posee las caractersticas principales de un lenguaje orientado a objetos. Fue creado para hacer programas de simulacin, en donde los "objetos" son la representacin de la informacin ms importante. Smalltalk (1972 a 1980) es posiblemente el ejemplo cannico, y con el que gran parte de la teora de la programacin orientada a objetos se ha desarrollado.

Entre los lenguajes orientados a objetos se destacan los siguientes: ABAP -> SAP Lenguaje orientado a eventos Oz ABL Lenguaje de programacin de OpenEdge de R Progress Software Perl (soporta herencia mltiple. La resolucin se ActionScript realiza en preorden, pero puede modificarse al ActionScript 3 algoritmo linearization C3 por medio del Ada mdulo Class::C3 en CPAN) C++ PHP (a partir de su versin 5) C# PowerBuilder Clarion Python Clipper (lenguaje de programacin) (Versin 5.x Ruby con librera de objetos Class(y)) Smalltalk (Entorno de objetos puro) D Magik (SmallWorld) Object Pascal (Embarcadero Delphi) Vala Gambas VB.NET Genie Visual FoxPro (en su versin 6) Harbour Visual Basic 6.0 Eiffel Visual DataFlex Fortran 90/95 Visual Objects Java XBase++ JavaScript (la herencia se realiza por medio de Lenguaje DRP la programacin basada en prototipos) Lenguaje de programacin Lexico (en castellano) Scala (lenguaje usado Objective-C por Twitter) http://www.scala-lang.org/page.jsp Ocaml Muchos de estos lenguajes de programacin no son puramente orientados a objetos, sino que son hbridos que combinan la POO con otros paradigmas. Al igual que C++ otros lenguajes, como OOCOBOL, OOLISP, OOPROLOG y Object REXX, han sido creados aadiendo extensiones orientadas a objetos a un lenguaje de programacin clsico. Un nuevo paso en la abstraccin de paradigmas de programacin es la Programacin Orientada a Aspectos (POA). Aunque es todava una metodologa en estado de maduracin, cada vez atrae a ms investigadores e incluso proyectos comerciales en todo el mundo.

También podría gustarte