Académique Documents
Professionnel Documents
Culture Documents
Se dice que algo es recursivo si se define en funcin de s mismo o a s mismo. Tambin se dice que nunca se debe incluir la misma palabra en la definicin de sta. El caso es que las definiciones recursivas aparecen con frecuencia en matemticas, e incluso en la vida real. Un ejemplo basta con apuntar una cmara al monitor que muestra la imagen que muestra esa cmara. El efecto es verdaderamente curioso, en especial cuando se mueve la cmara alrededor del monitor. En matemticas, tenemos m!ltiples definiciones recursivas " #!meros naturales $%& % es n!mero natural. $'& el siguiente n!mero de un n!mero natural es un n!mero natural " El factorial n(, de un n!mero natural $incluido el )& $%& si n * ) entonces )( * % $'& si n + ) entonces n( * n , $n"%&( -simismo, puede definirse un programa en trminos recursivos, como una serie de pasos bsicos, o paso base $tambin conocido como condicin de parada&, . un paso recursivo, donde vuelve a llamarse al programa. En un computador, esta serie de pasos recursivos debe ser finita, terminando con un paso base. Es decir, a cada paso recursivo se reduce el n!mero de pasos que /a. que dar para terminar, llegando un momento en el que no se verifica la condicin de paso a la recursividad. #i el paso base ni el paso recursivo son necesariamente !nicos. 0or otra parte, la recursividad tambin puede ser indirecta, si tenemos un procedimiento 0 que llama a otro 1 . ste a su ve2 llama a 0. Tambin en estos casos debe /aber una condicin de parada. E3isten ciertas estructuras cu.a definicin es recursiva, tales como los rboles, . los algoritmos que utili2an rboles suelen ser en general recursivos. Un ejemplo de programa recursivo en 4, el factorial int factorial(int n) { if (n == 0) return 1; return n * factorial(n-1); } 4omo se observa, en cada llamada recursiva se reduce el valor de n, llegando el caso en el que n es ) . no efect!a ms llamadas recursivas. 5a. que apuntar que el factorial puede obtenerse con facilidad sin necesidad de emplear funciones recursivas, es ms, el
uso del programa anterior es mu. ineficiente, pero es un ejemplo mu. claro. - continuacin se e3pone un ejemplo de programa que utili2a recursin indirecta, . nos dice si un n!mero es par o impar. -l igual que el programa anterior, /a. otro mtodo muc/o ms sencillo de determinar si un n!mero es par o impar, basta con determinar el resto de la divisin entre dos. 0or ejemplo si /acemos par$'& devuelve % $cierto&. Si /acemos impar$6& devuelve ) $falso&. /* declaracion de funciones, para evitar errores */ int par(int n); int impar(int n); int par(int n) { if (n == 0) return 1; return impar(n-1); } int impar(int n) { if (n == 0) return 0; return par(n-1); } En 0ascal se /ace as $notar el uso de for7ard& function impar(n : Integer) : oolean; for!ard; function par(n : Integer) : oolean; for!ard; function par(n : Integer) : "egin if n = 0 t#en par := true else par := impar(n$1) end; oolean;
function impar(n : Integer) : oolean; "egin if n = 0 t#en impar := false else impar := par(n$1) end;
Ejemplo si /acemos la llamada impar$8& /ace las siguientes llamadas par$'& impar$%& par$)& "+ devuelve % $cierto&
Ejercicio
<a famosa sucesin de 9ibonacci puede definirse en trminos de recurrencia de la
siguiente manera $%& 9ib$%& * % = 9ib$)& * ) $'& 9ib$n& * 9ib$n"%& > 9ib$n"'& si n +* ' ?4uantas llamadas recursivas se producen para 9ib$@&A. 4odificar un programa que calcule 9ib$n& de forma iterativa. #ota no utili2ar estructuras de datos, puesto que no queremos almacenar los n!meros de 9ibonacci anteriores a n= s se permiten variables au3iliares.
- Dado un arra# constituido de n meros enteros # que contiene ' elementos siendo ' () *+ devolver la suma de todos los elementos& int sumarra'(int numeros(), int posicion, int *) { if (posicion == *$1) return numeros(posicion); else return numeros(posicion) + sumarra'(numeros, posicion+1, *);
} ,,, int numeros(-) = {%,0,$1,1,&}; int * = -; printf(./d0n.,sumarra'(numeros, 0, *)); #otar que la condicin de parada se cumple cuando se llega al final del arra.. :tra alternativa es recorrer el arra. desde el final /asta el principio $de derecha a izquierda& int sumarra'(int numeros(), int posicion) { if (posicion == 0) return numeros(posicion); else return numeros(posicion) + sumarra'(numeros, posicion$1); } ,,, int numeros(-) = {%,0,$1,1,&}; int * = -; printf(./d0n.,sumarra'(numeros, *$1));
- Dado un arra# constituido de n meros enteros+ devolver la suma de todos los elementos& En este caso se desconoce el n mero de elementos& En cualquier caso se garantiza que el ltimo elemento del arra# es -*+ n mero que no aparecer en ninguna otra posicin& int sumarra'(int numeros(), int posicion) { if (numeros(posicion) == $1) return 0; else return numeros(posicion) + sumarra'(numeros, posicion+1); } ,,, int numeros(-) = {%,1,1,$&,$1}; printf(./d0n.,sumarra'(numeros, 0));
<a ra2n por la que se inclu.e este ejemplo se debe a que en general no se conocer el n!mero de elementos de la estructura de datos sobre la que se trabaja. En ese caso se introduce un centinela "como la constante "% de este ejemplo o la constante #U<: para punteros, u otros valores como el ma.or o menor entero que la mquina pueda representar" para indicar el fin de la estructura.
- Dado un arra# constituido de n meros enteros # que contiene ' elementos siendo ' () *+ devolver el elemento ma#or& int ma'or(int numeros(), int posicion) { int au2; if (posicion == 0) return numeros(posicion);
else { au2 = ma'or(numeros, posicion$1); if (numeros(posicion) 3 au2) return numeros(posicion); else return au2; }
- ,hora uno un poco ms complicado- dados dos arra#s de n meros enteros , # . de longitud n # m respectivamente+ siendo n () m+ determinar si . est contenido en ,& Ejemplo, ) /0+1+2+3+4+5+-16 . ) /5+-16 -( contenido7 . ) /3+56 -( no contenido7 . ) /1+06 -( no contenido 0ara resolverlo, se parte del primer elemento de - . se compara a partir de a/ con todos los elementos de C /asta llegar al final de C o encontrar una diferencia. - * D',8,6,EF, C * D8,6F "" ',8,6,E 8,6 G En el caso de encontrar una diferencia se despla2a al segundo elemento de - . as sucesivamente /asta demostrar que C es igual a un subarra. de - o que C tiene una longitud ma.or que el subarra. de -. 8,6,E 8,6 Histo de forma grfica consiste en desli2ar C a lo largo de - . comprobar que en alguna posicin C se suporpone sobre -. Se /an escrito dos funciones para resolverlo, contenido . es8u$arra#. <a primera devuelve cierto si el subarra. - . el arra. C son iguales= tiene dos condiciones de parada o que se /a.a recorrido C completo o que no coincidan dos elementos. <a segunda funcin es la principal, . su cometido es ir Idesli2andoI C a lo largo de -, . en cada paso recursivo llamar una ve2 a la funcin contenido= tiene dos condiciones de parada que el arra. C sea ma.or que el subarra. - o que C est contenido en un subarra. -. int contenido(int 4(), int (), int m, int pos, int desp) { if (pos == m) return 1; else if (4(desp+pos) == (pos)) return contenido(4, ,m, pos+1, desp); else return 0; }
int es5u"arra'(int 4(), int (), int n, int m, int desp) { if (desp+m 3 n) return 0; else if (contenido(4, , m, 0, desp)) return 1; else return es5u"arra'(4, , n, m, desp+1); } ,,, int 4(1) = {%, &, 1, -}; int (&) = {&, 1, -}; if (es5u"arra'(4, , 1, -, 0)) printf(.0n esta contenido en 4.); else printf(.0n no esta contenido en 4.); 5a. que observar que el requisito n +* m indicando en el enunciado es innecesario, si m + n entonces devolver falso nada ms entrar en la ejecucin de es8u$arra#. Este algoritmo permite /acer b!squedas de palabras en te3tos. Sin embargo e3isten algoritmos mejores como el de Jnut/"Korris"0rat, el de ;abin"Jarp o mediante autmatas finitos= estos algoritmos som ms complicados pero muc/o ms efectivos.
- Dado un arra# constituido de n meros enteros # que contiene ' elementos siendo ' () *+ devolver el elemento ma#or& En este caso escri$ir un procedimiento+ es decir+ que el elemento ma#or devuelto sea una varia$le que se pasa por re9erencia& void ma'or(int numeros(), int posicion, int *m) { if (posicion == 0) *m = numeros(posicion); else { ma'or(numeros, posicion$1, m); if (numeros(posicion) 3 *m) *m = numeros(posicion); } } ,,, int numeros(-) = {%,1,1,$&,$1}; int 6; ma'or(numeros, -$1, 76); printf(./d0n., 6);
5a. que tener cuidado con dos errores mu. comunes el primero es declarar la variable para que se pase por valor . no por referencia, con lo cual no se obtiene nada. El otro error consiste en llamar a la funcin pasando en lugar del parmetro por referencia una constante, por ejemplo ma.or$numeros, E"%, )&= en este caso adems se producir un error de compilacin.
manera-cLermann$), n& * n > % -cLermann$m, )& * -$m"%, %& -cLermann$m, n& * -$m"%, -$m, n"%&& -unque pare2ca mentira, siempre se llega al caso base . la funcin termina. 0robar a ejecutar esta funcin con diversos valores de n . m... Mque no sean mu. grandes(. En Nnternet pueden encontrarse algunas cosas curiosas sobre esta funcin . sus aplicaciones.
Ejercicios propuestos
Nota: para resolver los ejercicios basta con /acer un !nico recorrido sobre el arra.. Tampoco debe utili2arse ning!n arra. au3iliar, pero si se podrn utili2ar variables de tipo entero o booleano. - Dado un arra# constituido de n meros enteros # que contiene ' elementos siendo ' () *+ escri$ir una 9uncin que devuelva la suma de todos los elementos ma#ores que el ltimo elemento del arra#& - Dado un arra# constituido de n meros enteros # que contiene ' elementos siendo ' () *+ escri$ir una 9uncin que devuelva cierto si la suma de la primera mitad de los enteros del arra# es igual a la suma de la segunda mitad de los enteros del arra#& - Dados dos arra#s , # . de longitud n # m respectivamente+ n () m cu#os elementos estn ordenados # no se repiten+ determinar si todos los elementos de . estn contenidos en ,& <ecordar que los elementos estn ordenados+ de esta manera $asta con realizar un nico recorrido so$re cada arra#&
Conclusiones
En esta seccin se /a pretendido mostrar que la recursividad es una /erramienta potente para resolver m!ltiples problemas. Es ms, todo programa iterativo puede reali2arse empleando e3presiones recursivas . viceversa.