Vous êtes sur la page 1sur 8

Recursividad

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&

0or lo tanto 8 es un n!mero impar.

Qu pasa si se hace una llamada recursiva que no termina?


4ada llamada recursiva almacena los parmetros que se pasaron al procedimiento, . otras variables necesarias para el correcto funcionamiento del programa. 0or tanto si se produce una llamada recursiva infinita, esto es, que no termina nunca, llega un momento en el que no quedar memoria para almacenar ms datos, . en ese momento se abortar la ejecucin del programa. 0ara probar esto se puede intentar /acer esta llamada en el programa factorial definido anteriormente factorial($1); 0or supuesto no /a. que pasar parmetros a una funcin que estn fuera de su dominio, pues el factorial est definido solamente para n!meros naturales, pero es un ejemplo claro.

Cundo utilizar la recursin?


0ara empe2ar, algunos lenguajes de programacin no admiten el uso de recursividad, como por ejemplo el ensamblador o el 9:;T;-#. Es obvio que en ese caso se requerir una solucin no recursiva $iterativa&. Tampoco se debe utili2ar cuando la solucin iterativa sea clara a simple vista. Sin embargo, en otros casos, obtener una solucin iterativa es muc/o ms complicado que una solucin recursiva, . es entonces cuando se puede plantear la duda de si merece la pena transformar la solucin recursiva en otra iterativa. 0osteriormente se e3plicar como eliminar la recursin, . se basa en almacenar en una pila los valores de las variables locales que /a.a para un procedimiento en cada llamada recursiva. Esto reduce la claridad del programa. -!n as, /a. que considerar que el compilador transformar la solucin recursiva en una iterativa, utili2ando una pila, para cuando compile al cdigo del computador. 0or otra parte, casi todos los algoritmos basados en los esquemas de vuelta atrs . divide . vencers son recursivos, pues de alguna manera parece muc/o ms natural una solucin recursiva. -unque pare2ca mentira, es en general muc/o ms sencillo escribir un programa recursivo que su equivalente iterativo. Si el lector no se lo cree, posiblemente se deba a que no domine todava la recursividad. Se propondrn diversos ejemplos de programas recursivos de diversa complejidad para acostumbrarse a la recursin.

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.

Ejemplos de programas recursivos


- Dados dos n meros a !n mero entero" # $ !n mero natural ma#or o igual que cero" determinar a%$& int potencia(int a, int ") { if (" == 0) return 1; else return a * potencia(a, "$1); } <a condicin de parada se cumple cuando el e3ponente es cero. 0or ejemplo, la evaluacin de potencia($%, &) es potencia$"', 8& "+ $"'& , potencia$"', '& "+ $"'& , $"'& , potencia$"', %& "+ $"'& , $"'& , $"'& , potencia$"', )& "+ $"'& , $"'& , $"'& , % . a la vuelta de la recursin se tiene $"'& , $"'& , (-2) 1 /=/ $"'& , $"'& , (-2) potencia(-2,0) B $"'& , (-2) (-2) /=/ $"'& , (-2) potencia(-2, 1) B (-2) 4 /=/ (-2) potencia(-2,2) B -8 /=/ potencia(-2,3) en negrita se /a resaltado la parte de la e3presin que se eval!a en cada llamada recursiva.

- 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);

} ,,, int numeros(-) = {%,1,1,$&,$1}; int * = -; printf(./d0n., ma'or(numeros, 1));

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.

- :a 9uncin de ,c;ermann+ siendo n # m n meros naturales+ se de9ine de la siguiente

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.

Vous aimerez peut-être aussi