Está en la página 1de 36

FACULTAD DE INGENIERÍA

Escuela Profesional de Ingeniería de Sistemas y


Computación

Asignatura: Algoritmos y Estructuras de Datos

Mg. Jaime Ortíz Fernández


e-mail: d.jortiz@upla.edu.pe

HUANCAYO - 2022
UNIDAD II COLAS Y RECURSIVIDAD

TEMA: Recursividad

Diapositivas: Mg. Jaime Ortíz Fernández


Matrushka
• La Matrushka es una artesanía tradicional rusa. Es una muñeca de
madera que contiene otra muñeca más pequeña dentro de sí. Ésta
muñeca, también contiene otra muñeca dentro. Y así, una dentro
de otra.
Recursión
• Un árbol se crea recursivamente
¿Qué será que algo sea recursivo?
• ¿Por qué un árbol es una estructura recursiva?
• ¿De qué está formado un árbol?,
• ¿y cada elemento?
Recursividad
 Implica plantear la resolución del problema con otra estrategia:

¿Cómo puedo resolver el problema?

Si me dieran la solución de un problema un poco menos complejo...


¿A partir de esa solución podría obtener la solución del problema original?

=
Prob(n) Soluc(n)

Reducción Combinación

Prob(n-a)
Prob(n-a) = Soluc(n-a)
Soluc(n-a)

 En ese caso, sigue reducciendo el problema hasta que sea trivial


Recursividad: el concepto

• La recursividad es un concepto fundamental en


matemáticas y en computación.
• Es una alternativa diferente para implementar
estructuras de repetición (ciclos). Los módulos se
hacen llamadas recursivas.
• Se puede usar en toda situación en la cual la
solución pueda ser expresada como una secuencia
de movimientos, pasos o transformaciones
gobernadas por un conjunto de reglas no ambiguas.
Funciones recursivas

Cuando algo se define en términos de partes de sí


mismo más pequeñas o mas simples, se dice que es
recursivo.
La recursión es una técnica algorítmica donde una
función, para cumplir una tarea, se llama a sí misma
como parte de la tarea.
Se dice que una función es recursiva, si la función se
define en términos de si misma o se llama a sí misma
directa o indirectamente.
Método de las 3 preguntas
Utilizaremos este método para verificar que una solución
recursiva funciona. Para esto la función debe ser capaz
de contestar “si” a las siguientes tres preguntas.
• La pregunta caso-base: ¿Hay una salida no recursiva de la
función y la rutina funciona correctamente para este caso
base?
• La pregunta llamador-mas-pequeño: ¿Cada llamada
recursiva se refiere a un caso más pequeño del problema
original y tiende al caso base?
• La pregunta caso-general: suponiendo que las llamadas
recursivas funcionan correctamente, ¿funciona
correctamente toda la función?
Función recursiva
Las funciones recursivas se componen de:
• Caso base: una solución simple para un caso particular
(puede haber más de un caso base).

• Caso recursivo: una solución que involucra volver a utilizar la


función original, con parámetros que se acercan más al caso
base. Los pasos que sigue el caso recursivo son los
siguientes:
1. El procedimiento o método se llama a sí mismo
2. El problema se resuelve, tratando el mismo problema
pero de tamaño menor
3. La manera en la cual el tamaño del problema disminuye
asegura que el caso base eventualmente se alcanzará
Ejemplo: factorial
Escribe un programa que calcule el factorial (!) de
un entero no negativo. He aquí algunos ejemplos
de factoriales:

• 1! = 1
• 2! = 2  2*1
• 3! = 6  3*2*1
• 4! = 24  4*3*2*1
• 5! = 120  5*4*3*2*1
Ejemplo función recursiva
Recordemos como se define el factorial de un número?
n! = n*(n-1)*(n-2)*...*2*1 donde n>=0 y 0!=1
Entonces, ¿cómo podemos definir n! en términos de sí
mismo?, es decir de otro factorial.
n! = n*(n-1)*(n-2)*...*2*1  (n-1)!
n! = n * (n-1)!
(n-1)! = (n-1) * (n-2)!
....
2! = 2*1!
1! = 1*0!
0! = 1
Ejemplo función recursiva
El factorial de un número ilustra muy bien
los aspectos básicos de un problema
recursivo
• Se resuelve en términos de sí mismo con
un valor más pequeño n-1 (caso recursivo)
• Tiene una condición de terminación (caso
base) en donde se calcula directamente el
resultado
0! = 1
Esto es, tiene un fin!! En algún momento
termina.
Ejemplo: factorial (iterativo - repetetitivo)
int factorial (int n) public int factorial (int n) {

comienza int fact = 1;


for (int i = 1; i <= n; i++)
fact  1
fact = i * fact;
para i  1 hasta n
return fact;
fact  i * fact
}
regresa fact
termina
Ejemplo: factorial (recursivo)
int factorial (int n) public int factorial (int n) {
comienza if n == 0 return 1;
si n = 0 entonces
else
regresa 1
return factorial (n-1) * n;
otro
regresa factorial (n-1)*n }
termina
Ejemplo:
 A continuación se puede ver la secuencia de
factoriales.

 0! =1
 1! = 1 =1*1 = 1 * 0!
 2! = 2 =2*1 = 2 * 1!
 3! = 6 =3*2 *1 = 3 * 2!
 4! = 24 = 4 * 3 * 2 * 1 = 4 * 3!
 5! = 120 = 5 * 4 * 3 * 2 * 1 = 5 * 4!
 ...
 N! = = N * (N – 1)!
¿Cómo le hace?
120 El fact(5) = 120
Llamada en el
main fact(5)
5! 120
5 * 4! 24

4 * 3! 6
3 * 2! 2
2* 1! 1

1 * 0! 1 Valor de
1 regreso
Solución
Aquí podemos ver la secuencia que toma el factorial

1 si N = 0 (base)
N! =

N * (N – 1) ! si N > 0 (recursión)

Un razonamiento recursivo tiene dos partes: la base y la regla


recursiva de construcción. La base no es recursiva y es el
punto tanto de partida como de terminación de la definición.
Solución Recursiva
Dado un entero no negativo x, regresar el factorial de x fact:
Entrada n entero no negativo,
Salida:entero. Es importante determinar
un caso base, es decir un
int fact (int n) punto en el cual existe una
condición por la cual no se
{ requiera volver a llamar a
if (n == 0) la misma función.
return 1;
else
return fact(n – 1) * n ;
}
¿Cómo funciona la recursividad?
Llamadas recursivas

Resultados de las llamadas recursivas


¿Cómo funciona la recursividad?
Pila de recursión
Memoria

Segmento de
código
Está destinado a las variables
Segmento de
locales, parámetros de la
datos
función que se está
ejecutando y su valor de Segmento
regreso extra ( o
libre)
int suma(int x, int y) { Segmento de
int z; stack (pila)
z = x +y;
return z; Segmento del
} sistema
Llamada a una función iterativa
// función iterativa
int fact(int n) {
int f=1;
if(n==0|| n== 1)
return 1;
for(int i=1;i<=n; i++)
f *= i; i=1
return f;
} f=1
n=3
main() {
Regreso fact(3)
int f;
f = fact(3);
}
Ejemplo llamada recursiva

//función recursiva
int fact(int n) {
if(n==0)
return 1;
return (n*fact(n-1)); n=0
}
Regreso 1 *fact(0)
main() { n=1
int f; Regreso 2 *fact(1)
f = fact(3);
{ n=2
Regreso 3 *fact(2)
n=3
Regreso fact(3)
Recursividad vs. Iteración
Recursividad Iteración
Eficiencia en Puede requerir gastos Más eficiente
espacio considerables, sobre todo en
almacenamiento, ya que debe
guardar copias de variables
locales
Eficiencia en El tiempo de una llamada es Los ciclos son directos
tiempo costosa

Capacidad de Algunos valores son calculados La eficiencia en tiempo


computadora una y otra vez excediendo la y espacio permiten
capacidad de la computadora llegar en algunos casos
antes de obtener una respuesta a soluciones
Claridad en la En algunos casos la solución Mayor código y más
solución recursiva es más simple y variables lo hacen mas
natural. Utiliza menos código complicado
¿Por qué escribir programas recursivos?

• Son mas cercanos a la descripción matemática.


• Generalmente mas fáciles de analizar
• Se adaptan mejor a las estructuras de datos
recursivas.
• Los algoritmos recursivos ofrecen soluciones
estructuradas, modulares y elegantemente simples.
Factible de utilizar recursividad
• Para simplificar el código.
• Cuando la estructura de datos es recursiva
ejemplo : árboles.

No factible utilizar recursividad


• Cuando los métodos usen arreglos largos.
• Cuando el método cambia de manera
impredecible de campos.
• Cuando las iteraciones sean la mejor opción.
Recursión vs iteración
Repetición
Iteración: ciclo explícito (se expresa claramente)
Recursión: repetidas invocaciones a método
Terminación
Iteración: el ciclo termina o la condición del ciclo falla
Recursión: se reconoce el caso base

En ambos casos podemos tener ciclos infinitos

Considerar que resulta más positivo para cada problema

• LA RECURSIVIDAD SE DEBE USAR CUANDO SEA REALMENTE NECESARIA,


ES DECIR, CUANDO NO EXISTA UNA SOLUCIÓN ITERATIVA SIMPLE.
Las torres de Hanoi
Torres de Hanoi
Un problema típico a resolver con recursión es el de las Torres de
Hanoi, ya que al aplicar esta herramienta el problema se simplifica
enormemente. Las Torres de Hanói es un rompecabezas o juego
matemático inventado en 1883 por el matemático francés Éduard
Lucas

Consiste en tres varillas verticales y un número indeterminado de discos que


determinarán la complejidad de la solución. No hay dos discos iguales, están
colocados de mayor a menor en la primera varilla ascendentemente, y no se
puede colocar ningún disco mayor sobre uno menor a él en ningún
momento..
Torres de Hanoi
• La leyenda cuenta que en un templo del lejano
oriente, los sacerdotes intentaban mover una pila
de discos de una estaca a otra.
• La pila inicial tenía 64 discos ensartados en una
estaca, y estaban acomodados de abajo hacia
arriba en orden de tamaño decreciente.
Torres de Hanoi
• Los sacerdotes intentan mover la pila de discos de
una estaca hacia una segunda estaca, con las
restricciones de:
• Mover un solo disco a la vez
• Ningún disco más grande debe colocarse encima de uno
más pequeño
• Una tercera estaca está disponible para alojar
temporalmente a los discos
Torres de Hanoi
• Se supone que, el mundo se arreglará
cuando los sacerdotes completen su tarea.
• Por lo cual tenemos grandes incentivos para
ayudarles a solucionar el problema
• Supongamos que los sacerdotes intentan
mover los discos de la estaca 1 a la 3.
Torres de Hanoi

1 2 3
• Ejemplo con 3 estacas y 4 discos
Dividir para vencer
• Muchas veces es posible dividir un problema en
subproblemas más pequeños, generalmente del mismo
tamaño, resolver los subproblemas y entonces
combinar sus soluciones para obtener la solución del
problema original.

• Dividir para vencer es una técnica natural para las


estructuras de datos, ya que por definición están
compuestas por piezas. Cuando una estructura de
tamaño finito se divide, las últimas piezas ya no podrán
ser divididas.

También podría gustarte