Documente Academic
Documente Profesional
Documente Cultură
La recursin y cmo
puede ser que funcione
Estamos acostumbrados a escribir funciones que llaman a otras
funciones. Pero lo cierto es que nada impide que en Python (y en
muchos otros lenguajes) una funcin se llame a s misma. Y lo ms
interesante es que esta propiedad, que se llama recursin, permite en
muchos casos encontrar soluciones muy elegantes para determinados
problemas.
En materias de matemtica se estudian los razonamientos por induccin
para probar propiedades de nmeros enteros, la recursin no es ms que
una generalizacin de la induccin a ms estructuras: las listas, las
cadenas de caracteres, las funciones, etc.
A continuacin estudiaremos diversas situaciones en las cuales aparece
la recursin, veremos cmo es que esto puede funcionar, algunas
situaciones en las que es conveniente utilizarla y otras situaciones
x! = x (x 1)! si x > 0, 0! = 1
return n * factorial(n-1)
f = factorial(n-1)
r=n*f
return r
Instruccin
Contexto
de factorial
Resultado
factorial(3)
n3
if n == 0:
n3
Instruccin
Contexto
de factorial
Resultado
f = factorial (n-1)
n3
Se suspende el clculo. Se
llama afactorial(2)
factorial(2)
n2/n3
if n == 0:
n2/n3
f = factorial (n-1)
n2/n3
Se suspende el clculo. Se
llama afactorial(1)
factorial(1)
n1/n2/n3
if n == 0:
n1/n2/n3
f = factorial (n-1)
n1/n2/n3
Se suspende el clculo. Se
llama afactorial(0)
factorial(0)
n0/n1/n
2/n3
if n == 0:
n0/n1/n
2/n3
Instruccin
Contexto
de factorial
Resultado
r=1
n0r1/n
1 / n 2/ n 3
En factorial(0): return r
n1f1
n2/n3
r=n*f
n1f1r1/n
2 /n 3
En factorial(1): return r
n2f1
n3
r=n*f
n2f1r2/n
3
En factorial(2): return r
n3f2
En factorial(3): return r
n3f2
r=n*f
n3f2r6
En factorial(1): f = factorial
(n-1)
En factorial(2): f = factorial
(n-1)
Instruccin
Contexto
de factorial
Resultado
return r
Pila vaca
Devuelve el valor 6
18.6. Algoritmos
recursivos y algoritmos
iterativos
Llamaremos algoritmos recursivos a aquellos que realizan llamadas
recursivas para llegar al resultado, yalgoritmos iterativos a aquellos que
llegan a un resultado a travs de una iteracin mediante un ciclo definido
o indefinido.
Todo algoritmo recursivo puede expresarse como iterativo y viceversa.
Sin embargo, segn las condiciones del problema a resolver podr ser
preferible utilizar la solucin recursiva o la iterativa.
fact = 1
for num in xrange(n, 1, -1):
fact *= num
return fact
18.7. Un ejemplo de
recursividad elegante
# Caso base
if n <= 0:
return 1
# n par
if n % 2 == 0:
pot = potencia(b, n/2)
return pot * pot
# n impar
else:
pot = potencia(b, (n-1)/2)
return pot * pot * b
# b 2 n 10
pot = potencia(2,2)
#b2n5
pot = potencia(2,1)
#b2n2
pot = potencia(2,0) # b 2 n 1
return 1
return 1 * 1 * 2
return 2 * 2
return 4 * 4 * 2
return 32 * 32
#b2n0
# b 2 n 1 pot 1
# b 2 n 2 pot 2
# b 2 n 5 pot 4
# b 2 n 10 pot 32
pila = []
while n > 0:
if n % 2 == 0:
pila.append(True)
n /= 2
else:
pila.append(False)
n = (n-1)/2
pot = 1
while pila:
es_par = pila.pop()
if es_par:
return pot
18.8. Un ejemplo de
recursividad poco eficiente
Del ejemplo anterior se podra deducir que siempre es mejor utilizar
algoritmos recursivos, sin embargo - como ya se dijo - cada situacin
debe ser analizada por separado.
Un ejemplo clsico en el cual la recursividad tiene un resultado muy poco
eficiente es el de los nmeros de fibonacci. La sucesin de fibonacci est
definida por la siguiente relacin:
fib(0) = 0
fib(1) = 1
ant2 = 0
ant1 = 1
for i in xrange(2, n+1):
fibn = ant1 + ant2
ant2 = ant1
ant1 = fibn
return fibn
Vemos que el caso base es el mismo para ambos algoritmos, pero que
en el caso iterativo se calcula el nmero de Fibonacci de forma
incremental, de modo que para obtener el valor de fib(n) se harn n
1 iteraciones.
18.9. Limitaciones
Si creamos una funcin sin caso base, obtendremos el equivalente
recursivo de un bucle infinito. Sin embargo, como cada llamada recursiva
agrega un elemento a la pila de llamadas a funciones y la memoria de
nuestras computadoras no es infinita, el ciclo deber terminarse cuando
se agote la memoria disponible.
En particular, en Python, para evitar que la memoria se termine, la pila de
ejecucin de funciones tiene un lmite. Es decir, que si se ejecuta un
cdigo como el que sigue:
def inutil(n):
return inutil(n-1)
>>> inutil(1)
File "<stdin>", line 2, in inutil
File "<stdin>", line 2, in inutil
(...)
File "<stdin>", line 2, in inutil
RuntimeError: maximum recursion depth exceeded
18.11. Ejercicios
Ejercicio 18.11.1. Escribir una funcin que reciba un nmero positivo n y
devuelva la cantidad de dgitos que tiene.
Ejercicio 18.11.2. Escribir una funcin que simule el siguiente
experimento: Se tiene una rata en una jaula con 3 caminos, entre los
cuales elige al azar (cada uno tiene la misma probabilidad), si elige el 1
luego de 3 minutos vuelve a la jaula, si elige el 2 luego de 5 minutos
vuelve a la jaula, en el caso de elegir el 3 luego de 7 minutos sale de la
jaula. La rata no aprende, siempre elige entre los 3 caminos con la misma
probabilidad, pero quiere su libertad, por lo que recorrer los caminos
hasta salir de la jaula.
La funcin debe devolver el tiempo que tarda la rata en salir de la jaula.
Ejercicio 18.11.3. Escribir una funcin que reciba 2 enteros n y b y
devuelva True si n es potencia de b. Ejemplos:
>>> es_potencia(8,2)
True
>>> es_potencia(64,4)
True
>>> es_potencia(70,10)
False
1 es impar.
Ejercicio 18.11.6. Escribir una funcin que calcule recursivamente el nsimo nmero triangular (el nmero 1 + 2 + 3 + ... + n).
Ejercicio 18.11.7. Escribir una funcin que calcule recursivamente
cuntos elementos hay en una pila, suponiendo que la pila slo tiene los
mtodos apilar y desapilar, y no altere el contenido de la pila.
Implementaras esta funcin para un programa real? Por qu?
Ejercicio 18.11.8. Escribir una funcion recursiva que encuentre el mayor
elemento de una lista.
Ejercicio 18.11.9. Escribir una funcin recursiva para replicar los
elementos de una lista una cantidad nde veces. Por ejemplo, replicar ([1,
3, 3, 7], 2) = ([1, 1, 3, 3, 3, 3, 7, 7])
http://librosweb.es/libro/algoritmos_python/capitulo_18/algoritmos_recursivos_y
_algoritmos_iterativos.html