0% encontró este documento útil (0 votos)
60 vistas22 páginas

Unidad 4 Recursión

Este documento explica el concepto de recursión, que es cuando una función se invoca a sí misma de forma directa o indirecta. Se definen las reglas de buena recursión como tener una condición de corte, solución trivial y acercamiento a la condición de corte. También se dan ejemplos como factorial y recorrer una lista vinculada de forma recursiva.

Cargado por

MakZ
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PPS, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
60 vistas22 páginas

Unidad 4 Recursión

Este documento explica el concepto de recursión, que es cuando una función se invoca a sí misma de forma directa o indirecta. Se definen las reglas de buena recursión como tener una condición de corte, solución trivial y acercamiento a la condición de corte. También se dan ejemplos como factorial y recorrer una lista vinculada de forma recursiva.

Cargado por

MakZ
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PPS, PDF, TXT o lee en línea desde Scribd

RECURSIÓN

Definición

Un procedimiento o función se dice recursivo


si durante su ejecución se invoca directa o
indirectamente a sí mismo. Esta invocación
depende al menos de una condición que
actúa como condición de corte que provoca
la finalización de la autoinvocación.
Definición

Repetición por autoreferencia, cuando una


función se invoca a sí misma (puede ser en
forma directa o indirecta).
Es la forma en la cual se especifica un proceso
basado en su propia definición, pero con
menor complejidad. De esta forma, en algún
momento se llega a un proceso muy simple
que puede resolverse facilmente (se llama
solución trivial).
Parece un concepto nuevo, pero ya lo hemos visto en
varias definiciones matemáticas…

Definiciones por inducción


El uno pertenece a los Naturales, y si N pertenece
a los Naturales, N+1 también.

Factorial(0) = 1 (solución trivial)


Factorial(N) = N * Factorial(N-1), para todo N > 0.

0!=1
N ! = N * (N - 1) !
Desarrollo de la función factorial

int factorial (int x)


{
int rta;
If ( x = = 0)
rta = 1;
else
rta = x * factorial (x-1) ;
return rta;
}
z = factorial(3)
{ int rta;
if (3 = = 0) rta = 1;
else
rta= 3 * factorial(2)
{ int rta;
if (2 = = 0) rta = 1;
else
rta= 2 * factorial(1)
{ int rta;
if (1 = = 0) rta = 1;
else
rta= 1 * factorial(0)
{ int rta;
if (0 = = 0) rta = 1;
else rta= 3 * factorial (-1);
return rta; return rta;}
return rta; }
}
return rta;
}
Cómo funciona esto ??

En el momento de realizar una invocación recursiva,


se suspende la ejecución de la función invocante
hasta que se termina de resolver la función
invocada.
Si bien es la misma función la que se invoca, se
genera un nuevo espacio de memoria para la
resolución de la misma.
Cada espacio tiene sus propias variables locales y
parámetros, con valores propios.
Para poder resolver factorial(3), primero se
debe resolver factorial(2), pero…

Para poder resolver factorial(2), primero se


debe resolver factorial(1), pero…

Para poder resolver factorial(1), primero se


debe resolver factorial(0), y…

factorial(0) es 1
Reglas de la buena recursión
Toda función recursiva debe tener:
1. Al menos una Condición de Corte con su
respectiva Solución Trivial.
2. Al menos una Llamada Recursiva (o Entrada
en Recursión).
3. En cada Llamada Recursiva, se vuelve a
invocar el mismo algoritmo, pero con un caso
más simple de resolver. Se produce un
acercamiento a la Condición de Corte.
4. Al llegar a la Solución Trivial, queda
expresada la solución total (considerando
toda la fórmula que quedó pendiente de
resolver).
int factorial (int x)
{
Condición de Corte
int rta;
If ( x = = 0)
Solución Trivial
rta = 1;
else
rta = x * factorial (x-1) ;
return rta; Acercamiento a la
} Condición de Corte

Llamada Recursiva
Usar recursión cuando:

1. La estructura de la función es recurrente y el


algoritmo resulta más sencillo.
2. La estructura de datos es recursiva.
Definición de Lista
estructura de datos recursiva

El NULL es una Lista y además, un


Nodo seguido de una Lista
también es Lista.
?
Ejemplo: recorrer una lista vinculada
Se trata de una estructura de datos recursiva. Considerar la
estructura que define al nodo.

void recorrer( Nodo * lista)


{
Condición de Corte
if (lista != NULL) Corta cuando es falso
{
printf(“%d”, lista->dato);
recorrer(lista->siguiente);
}
Acercamiento a la
} Llamada Recursiva Condición de Corte

Solución Trivial: ausencia de ELSE. No hace nada al llegar a NULL


Qué hace el siguiente código?
void recorrer( Nodo * lista)
{
if (lista != NULL)
{
recorrer(lista->siguiente);
printf(“%d”, lista->dato);
}
}
Tener en cuenta que para recorrer la lista NO hace
falta usar while ni for. Ni ningún otra estructura de
repetición. En vez de eso, se tiene que:

1. La recursión se encarga de repetir el algoritmo


(printf en este caso).
2. La Llamada Recursiva con el acercamiento a la
condición de corte hace que se avance en la lista.
3. La condición de corte finaliza el recorrido de la
lista, justo cuando la lista se termina.
4. La solución trivial resuelve el algoritmo para la
lista más simple, o sea la lista nula. Y la solución
es no hacer nada, en este caso no imprimir.
Cómo se piensa en forma recursiva ?
1. Encontrar la solución trivial.
2. Armar la expresión de la solución total
del problema, contando con la solución
al problema para una etapa “una vez
mas cercana” a la solución trivial.

Las reglas de la buena recursión completan


todo lo que falta para que esta forma
simple de razonamiento dé resultado.
Ejemplo: sumar el contenido de una lista de
enteros.

Para solucionar este problema planteo el siguiente algoritmo:

“La suma de una lista vacía es 0”


“La suma de los números de una lista será igual a la suma
entre el primero y el resultado de la suma de la sublista
siguiente.”

En este caso particular del ejemplo de la lista, se separa el


primer elemento y se supone conocida la solución de los
restantes. También se le llama “separarlo en cabeza y
cola”.
int suma(Nodo * lista)
{
int rta;
if(lista == NULL)
//“La suma de una lista vacía es 0”
rta = 0;
cabeza cola
else
rta = lista->dato + suma(lista->siguiente);
/*“La suma de los números de una lista será igual a la
suma entre el primero y el resultado de la suma de la
sublista siguiente.”*/
return rta;
}
Ejemplo: determinar si un arreglo es capicúa.

int capicua(int a[], int i, int j)


{ int rta;
if(i<j) //condición de corte
if(a[i] == a[j]) //condición de corte
rta = capicua(a, i+1, j -1); //recursión
else
rta = 0; //solución trivial
else
rta = 1; //solución trivial
return rta;
}
Relación entre Recursión e Iteración

Tanto la iteración como la recursión:


– se basan en una estructura de control: la iteración utiliza una
estructura de repetición y la recursión una estructura de
selección.
– incluyen repeticion: la iteración utiliza una estructura de
repetición de forma explícita; mientras que la recursión
consigue la repetición mediante llamadas de función
repetidas.
– incluyen una prueba de terminación: la iteración termina
cuando falla la condición de continuación del ciclo; la
recursión termina cuando se reconoce el caso base.
– pueden ocurrir de forma infinita: la iteración se puede quedar
en ciclo infinito si la condición del ciclo nunca se hace falsa;
la recursión se hará infinita si el paso de recursión no reduce
el problema de tal forma que converja al caso base.
La recursión invoca de manera repetida, y por lo tanto, puede
sobrecargar las llamadas de función. Esto puede resultar
costoso tanto en tiempo de procesador como en espacio de
memoria.
Recursión e Iteración
Si un lenguaje de programación como C provee tanto recursión como
iteración, cuál de los dos métodos debería ser usado para resolver un
problema dado?

En una solución recursiva el computador debe controlar y resolver


cada una de las invocaciones manteniendo información acerca del
resultado las mismas.

Esto puede ser costoso en tiempo y espacio.

En general, se recomienda el uso de una solución recursiva sólo en


caso que:

– la solución no puede ser fácilmente expresable iterativamente (sucede


frecuentemente).

– la eficiencia de la solución recursiva es satisfactoria.

También podría gustarte