Tema 1. Recursividad - us

39
Tema 1. Recursividad Análisis y Diseño de Algoritmos ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA Departamento de Lenguajes y Sistemas Informáticos Curso 2010-2011 Índice 1. Concepto 2. Tipos de Recursividad 3. Recursividad lineal 3.1. No final 3.2. Final 4. Recursividad Múltiple Análisis y Diseño de Algoritmos 2 4. Recursividad Múltiple 5. Transformación Recursión-Iteración 5.1 Iteración Lineal Final 5.2 Iteración Lineal No Final 5.3 Recursividad Múltiple e Iteraciones 6. Ejercicios

Transcript of Tema 1. Recursividad - us

Page 1: Tema 1. Recursividad - us

Tema 1. RecursividadAnálisis y Diseño de Algoritmos

ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

Departamento de Lenguajes y Sistemas InformáticosCurso 2010-2011

Índice

1. Concepto2. Tipos de Recursividad3. Recursividad lineal

3.1. No final3.2. Final

4. Recursividad Múltiple

Análisis y Diseño de Algoritmos 2

4. Recursividad Múltiple5. Transformación Recursión-Iteración

5.1 Iteración Lineal Final5.2 Iteración Lineal No Final5.3 Recursividad Múltiple e Iteraciones

6. Ejercicios

Page 2: Tema 1. Recursividad - us

1. Concepto

� Un algoritmo recursivo es aquél que expresa lasolución de un problema en términos de llamada ollamadas a sí mismo. Cada llamada a sí mismo sedenomina llamada recursiva.

T2 f( T1 n){

...

Análisis y Diseño de Algoritmos 3

� Los algoritmos recursivos son apropiados si la definicióndel problema está planteada de forma recursiva.

� La recursividad es una alternativa a la iteración, comoveremos más adelante.

...

v = f(...);

...

}

2. Tipos de recursividad

�Según el número de llamadas,� Recursividad simple o lineal : en cada llamada recursiva se

ejecuta, a lo sumo, una llamada a la propia función. Se puederepresentar gráficamente mediante una lista. Algunosejemplos son el factorial o la búsqueda dicotómica.

Análisis y Diseño de Algoritmos 4

� Recursividad múltiple : en cada llamada recursiva puedenejecutarse más de una llamada a la propia función. En estetema se considerarán sólo algoritmos recursivos múltiplescon 2 llamadas recursivas dentro de la misma función,aunque pudiera haber más. Este tipo de recursividad sepuede representar gráficamente mediante un árbol binario.Algunos ejemplos son el Quicksort o el cálculo del número deFibonacci.

Page 3: Tema 1. Recursividad - us

3. Recursividad Lineal

Análisis y Diseño de Algoritmos 5

Recursividad Lineal

� En una definición recursiva se distinguen, como mínimo, 2 partes:caso trivial o base y caso recursivo.

� Según la posición de la llamada recursiva, para el caso de larecursividad lineal se distinguen:a. Recursividad no final : tras la llamada recursiva se realiza un

6

a. Recursividad no final : tras la llamada recursiva se realiza unprocesamiento hasta llegar al resultado de la llamada.

b. Recursividad final : no hay procesamiento. El resultado de la llamadarecursiva coincide con el resultado final buscado.

Page 4: Tema 1. Recursividad - us

Recursividad Lineal

a. Definición recursiva de Factorial (Rec. no final):

n! =1 si n= 0

n (n-1)! si n >0 Caso RecursivoCaso Base

7

b. Definición ecursiva del Máximo Común Divisor (Rec. Final):

mcd(a,b) = a si b = 0

mcd(b,a%b) si b >0 Caso Recursivo

Caso Base

Recursividad Lineal No Final

� Representación gráfica del cálculo del Factorial para n = 4, donde cadanodo representa una llamada recursiva y tiene dos parámetros, n y r. Lafunción siguiente va transformando los datos de entrada. En este caso,siguiente(n) = n-1.

Caso base

4, r 3, r1 2, r2 1, r3 0, 1

siguiente(4) siguiente(3) siguiente(2) siguiente(1)

Análisis y Diseño de Algoritmos 8

� Una vez que se llega al caso base, si estamos en recursividad final, ya setiene el resultado. En cambio, si es no final, es necesario iterar hacia atráspara ir generando los resultados requeridos, como es el caso del factorial.En este caso, combina(n,r)=n*r

4, r 3, r1 2, r2 1, r3 0, 1

Caso base

4, 24 3, 6 2, 2 1, 1 0, 1

combina(1,1)combina(2,1)combina(3,2)combina(4,6)

Page 5: Tema 1. Recursividad - us

Recursividad Lineal Final

� Representación gráfica del cálculo del máximo común divisorde 20 y 15.

� Llamada inicial mcd(20,15).� Función siguiente(a,b) = <b,a%b>� siguiente(20,15) = <15,5>� siguiente(20,15) = <15,5>

Análisis y Diseño de Algoritmos 9

Caso base

(20,15) (15, 5) (5, 0)

siguiente(20,15) siguiente(15,5)

Recursividad Lineal

� En general, calcular recursivamente una solución consiste en:� En el caso de la recursividad final, ir calculando el siguiente

problema y realizar llamadas recursivas hasta que lleguemos alcaso base (ya tenemos el resultado requerido).

� En el caso de la recursividad no final, ir calculando el siguienteproblema y realizar llamadas recursivas hasta que lleguemos alcaso base, tras lo cual es necesario ir combinando los resultadosparciales hasta obtener el resultado requerido.

Análisis y Diseño de Algoritmos 10

parciales hasta obtener el resultado requerido.� La recursividad final puede verse como un caso particular de

la recursividad no final en el que combina(n, r) = r.� En general, para resolver problemas recursivos se propone

trabajar con:� Fichero de cabecera (.h): Incluye la definición de tipos y la

declaración de prototipos para las funciones.� Fichero fuente (.c): Incluye el código para las distintas funciones.� Programa principal (main).

Page 6: Tema 1. Recursividad - us

Recursividad Lineal No Final

RecLinealNoFinal.h

typedef enum{false, true} logico;T2 f( T1 n);logico esCasoBase (T1 n);T2 solucionBase (T1 n);T1 siguiente (T1 n);

Definición de tipos.

Declaración de prototipos.

Análisis y Diseño de Algoritmos 11

T1 siguiente (T1 n);T2 combina (T1 n, T2 rSig );

Para resolver un problema concreto, en el archivo “.h” T1 será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida.

Recursividad Lineal No Final

RecLinealNoFinal.c#include “RecLinealNoFinal.h”

// Esquema general para cualquier problema Rec No Final (común)

T2 f( T1 n) {

T1 nSig;

T2 r,rSig;

if ( esCasoBase (n)) {

Para resolver un problema concreto, en el archivo “.c” T1 será reemplazado por el tipo del

Análisis y Diseño de Algoritmos 12

if ( esCasoBase (n)) {

r = solucionBase(n);

}

else {

nSig = siguiente(n);

rSig = f(nSig);

r = combina(n, rSig);

}

return r;

}

será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida.

Page 7: Tema 1. Recursividad - us

Recursividad Lineal No Final

RecLinealNoFinal.c…

// Métodos específicos para el problema a resolver

logico esCasoBase( T1 n) {

}

T2 solucionBase( T1 n) {

Para resolver un problema concreto, en el archivo “.c” T1 será reemplazado por el tipo del

Análisis y Diseño de Algoritmos 13

T2 solucionBase( T1 n) {

}

T1 siguiente( T1 n) {

}

T2 combina( T1 n, T2 rSig) {

}

será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida. Además, se les dará código a los distintos métodos.

Recursividad Lineal No Final

Principal.c#include <stdio.h>

#include “RecLinealNoFinal.h”

void main ( void ) {

T1 n;

Para resolver un problema concreto, en el archivo “.c” T1 será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida.

Análisis y Diseño de Algoritmos 14

T2 r;

printf (“Introduzca el valor para la entrada: ”);

scanf (“%efT1”, &n);

r = f (n);

printf (“El resultado de la función recursiva para la entrada %efT1 es %efT2”,n,r);

} Especificadores de formato: %c carácter %d int%ld long %f float%lf double %s cadena de carácteres

Page 8: Tema 1. Recursividad - us

Ejemplo Rec No Final: Factorial

Factorial.h

typedef enum{false, true} logico ;int f( int n);logico esCasoBase (int n);int solucionBase (int n);int siguiente (int n);

Análisis y Diseño de Algoritmos 15

int siguiente (int n);int combina (int n, int rSig );

T1 y T2 han sido sustituidos por int .

Ejemplo Rec No Final: Factorial

Factorial.c#include “Factorial.h”

// Esquema general para cualquier problema Rec No Final (común)

int f( int n) {

int nSig;

int r,rSig;

if ( esCasoBase (n)) {

T1 y T2 han sido sustituidos por int .

Análisis y Diseño de Algoritmos 16

if ( esCasoBase (n)) {

r = solucionBase(n);

}

else {

nSig = siguiente(n);

rSig = f(nSig);

r = combina(n, rSig);

}

return r;

}

Page 9: Tema 1. Recursividad - us

Ejemplo Rec No Final: Factorial

Factorial.c…

// Métodos específicos para el problema a resolver

logico esCasoBase( int n) {

return n == 0 ;

}

int solucionBase( int n) {

T1 y T2 han sido sustituidos por int y los métodos han sido implementados.

Análisis y Diseño de Algoritmos 17

int solucionBase( int n) {

return 1;

}

int siguiente( int n) {

return n - 1 ;

}

int combina( int n, int rSig) {

return n * rSig ;

}

implementados.

Ejemplo Rec No Final: Factorial

Principal.c#include <stdio.h>

#include “Factorial.h”

void main ( void ) {

int n;

T1 y T2 han sido sustituidos por int .

Análisis y Diseño de Algoritmos 18

int r;

printf (“Introduzca el valor para la entrada: ”);

scanf (“%d”, &n);

r = f (n);

printf (“El resultado de la función recursiva para la entrada %d es %d”,n,r);

}

Especificadores de formato adecuados (%d int)

Page 10: Tema 1. Recursividad - us

Ejemplo Rec No Final: Factorial

void main ( void ) {

int n, r;

printf (“Introduzca el valor para la entrada: ”);

� La metodología anterior nos permite seguir unos pasos para resolver elproblema: esCasoBase, Siguiente, Combina, …� Una vez seguidos los pasos podemos desplegar las funciones del esquema yquedarnos con un método que resuelve el problema, sustituyendo en elesquema cada función (esCasoBase, …) por su cuerpo.

Análisis y Diseño de Algoritmos 19

printf (“Introduzca el valor para la entrada: ”);

scanf (“%d”, &n);

r = factorialRec (n);

printf (“El resultado para la entrada %d es %d”, n, r);

} int factorialRec( int n){

int r; if (n == 0)

r = 1;else

r = n * factorialRec (n - 1);return r;

}

Recursividad Lineal Final

� Para el caso de la recursividad lineal final, se seguiría elmismo esquema que para la no final, con laparticularidad de que el método combina presentasiempre la misma forma, independientemente delproblema que se esté resolviendo.

Análisis y Diseño de Algoritmos 20

// Método combina Rec Lineal Final

T2 combina( T1 n, T2 rSig) {return rSig;

}

Page 11: Tema 1. Recursividad - us

Múltiples parámetros de entrada

�Cuando el número de datos de entrada es mayorque uno, se proponen dos enfoques:� Usar un tipo auxiliar para gestionar dichos parámetros de

forma conjunta, empaquetando varios datos en uno através del uso de estructuras.través del uso de estructuras.

� Enfoque clásico: Definir tantos parámetros en el métodocomo datos de entrada se requieran.

�A continuación se verán ambos enfoques aplicadosal problema del cálculo del máximo común divisor(Rec. Lineal Final).

Análisis y Diseño de Algoritmos 21

Datos complejos: Estructuras

typedef struct{

T1 c1 ;

T2 c2 ;

� En función del número y tipo de los parámetros de entrada,se definen las estructuras DosDatos, TresDatos, … NDatos.

Análisis y Diseño de Algoritmos 22

T2 c2 ;

TN cn ;

} NDatos;

NDatos var ;

Page 12: Tema 1. Recursividad - us

Uso de estructuras para el mcd

Mcd.h

� Para el caso del mcd(a,b) , el tipo del parámetro de entrada(T1) es DosDatosInt , mientras el de salida (T2) es int .

� El par (a,b) se representa como una variable de tipoDosDatosInt , donde c1 representa al valor a, mientras c2representa a b.

Análisis y Diseño de Algoritmos 23

Mcd.htypedef enum{false, true} logico ;typedef struct{

int c1;int c2;

} DosDatosInt;int f (DosDatosInt n);logico esCasoBase (DosDatosInt n);int solucionBase (DosDatosInt n);DosDatosInt siguiente (DosDatosInt n);int combina (DosDatosInt n, int rSig );

Uso de estructuras para el mcd

Mcd.c#include “mcd.h”

int f (DosDatosInt n) {DosDatosInt nSig;int r,rSig;if (esCasoBase(n)) {

r = solucionBase(n);

Análisis y Diseño de Algoritmos 24

r = solucionBase(n);}else {

nSig = siguiente(n);rSig = f(nSig);r = combina(n, rSig);

}return r;

} …

Page 13: Tema 1. Recursividad - us

Uso de estructuras para el mcd

Mcd.c…logico esCasoBase (DosDatosInt n) {

return n.c2 == 0;} int solucionBase (DosDatosInt n) {

return n.c1;}

Mediante el operador “.” se accede a los miembros de la estructura.

Análisis y Diseño de Algoritmos 25

}DosDatosInt siguiente (DosDatosInt n) {

DosDatosInt nSig = {n.c2,n.c1%n.c2}; return nSig;

} int combina (DosDatosInt n, int rSig ) {

return rSig;}

Uso de estructuras para el mcd

Ppal.c#include <stdio.h>#include "mcd.h"

void main (void) {DosDatosInt n;int r ;printf ("Introduzca los valores para la entrada: ");

Análisis y Diseño de Algoritmos 26

printf ("Introduzca los valores para la entrada: ");scanf ("%d %d", &(n.c1), &(n.c2)); r = f (n);printf ("El resultado de la función recursiva es %d", r);

}

Page 14: Tema 1. Recursividad - us

Uso de estructuras para el mcd

void main (void) {

DosDatosInt n;

int r;

printf ("Introduzca los valores para la entrada: ");

scanf ("%d %d", &(n.c1), &(n.c2));

r = mcdRec(n);

� Nuevamente, desplegando las funciones del esquemaobtenemos un único método que resuelve el problema.

Análisis y Diseño de Algoritmos 27

r = mcdRec(n);

printf ("El resultado es %d", r);

}

int mcdRec(DosDatosInt n){

int r;

if (n.c2 == 0) {

r = n.c1;

}

else {

DosDatosInt nSig = {n.c2,n.c1%n.c2};

r = mcdRec(nSig);

}

return r;

}

Enfoque clásico para el mcd

� En el enfoque clásico, el dato de entrada se maneja comodos parámetros de tipo int .� Cuando dichos datos son el parámetro de salida de algúnmétodo (ej. siguiente ), es necesario pasarlos comoparámetros de entrada salida (por referencia).

Análisis y Diseño de Algoritmos 28

Mcd.htypedef enum{false, true} logico ;int f (int nC1, int nC2);logico esCasoBase (int nC1, int nC2);int solucionBase (int nC1, int nC2);void siguiente (int nC1, int nC2, int * nSigC1 , int * nSigC2 );int combina (int nC1, int nC2, int rSig );

Paso de parámetros por referencia.

Page 15: Tema 1. Recursividad - us

Enfoque clásico para el mcd

Mcd.c#include "mcd.h"

int f( int nC1, int nC2) {int nSigC1, nSigC2; int r,rSig;if ( esCasoBase (nC1,nC2)) {

r = solucionBase (nC1,nC2); Parámetros de entrada salida

Análisis y Diseño de Algoritmos 29

r = solucionBase (nC1,nC2);}else {

siguiente (nC1,nC2,&nSigC1,&nSigC2);rSig = f (nSigC1,nSigC2);r = combina (nC1,nC2,rSig);

}return r;

}…

entrada salida

Enfoque clásico para el mcd

Mcd.c…logico esCasoBase( int nC1, int nC2){

return nC2 == 0;}int solucionBase( int nC1, int nC2){

return nC1;}

Análisis y Diseño de Algoritmos 30

}void siguiente( int nC1, int nC2, int * nSigC1, int * nSigC2){

*nSigC1 = nC2;*nSigC2 = nC1%nC2;

}int combina( int nC1, int nC2, int rSig){

return rSig;}

Parámetros de entrada salida

Page 16: Tema 1. Recursividad - us

Enfoque clásico para el mcd

Ppal.c#include <stdio.h>#include "mcd.h"

void main ( void ) {int nC1,nC2; int r;printf ("Introduzca los valores para la entrada: ");

Análisis y Diseño de Algoritmos 31

printf ("Introduzca los valores para la entrada: ");scanf ("%d %d", &nC1, &nC2); r = f (nC1,nC2);printf ("El resultado de la función recursiva es %d", r);

}

Enfoque clásico para el mcd

void main ( void ) {

int nC1, nC2;

int r;

printf ("Introduzca los valores para la entrada: ");

scanf ("%d %d", &nC1, &nC2);

r = mcdRec(nC1,nC2);

� Nuevamente, desplegando las funciones del esquemaobtenemos un único método que resuelve el problema.

Análisis y Diseño de Algoritmos 32

r = mcdRec(nC1,nC2);

}

int mcdRec( int nC1, int nC2){

int r;

if (nC2 == 0) {

r = nC1;

}

else {

int nSigC1 = nC2;

int nSigC2 = nC1%nC2;

r = mcdRec(nSigC1, nSigC2);

}

return r;

}

Page 17: Tema 1. Recursividad - us

4. Recursividad Múltiple

Análisis y Diseño de Algoritmos 33

Recursividad Múltiple

� Como se ha comentado anteriormente, la recursividad múltiple sepuede representar gráficamente mediante un árbol binario dondecada nodo representa una llamada recursiva y tiene dos parámetros,n y r. En este caso es necesario definir funciones similares a las quese han definido para la recursividad lineal, con la diferencia de queahora se necesitan dos funciones siguientes (ya que hay dos

34

ahora se necesitan dos funciones siguientes (ya que hay dosllamadas recursivas) que establezcan las llamadas recursivas.

� Definición recursiva del número de Fibonacci:

si 0 1( )

( 1) ( 2) si 1

n nfib n

fib n fib n n

≤ ≤= − + − > Caso Recursivo

Caso Base

Page 18: Tema 1. Recursividad - us

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, r1

Análisis y Diseño de Algoritmos 35

2, r2

1, r4

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, r1

Análisis y Diseño de Algoritmos 36

2, r2

1, 1 0, r5

Page 19: Tema 1. Recursividad - us

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, r1

Análisis y Diseño de Algoritmos 37

2, r2

1, 1 0, 0

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, r1

Análisis y Diseño de Algoritmos 38

2, 1

1, 1 0, 0

Page 20: Tema 1. Recursividad - us

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, r1

Análisis y Diseño de Algoritmos 39

2, 1 1, r3

1, 1 0, 0

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, r1

Análisis y Diseño de Algoritmos 40

2, 1 1, 1

1, 1 0, 0

Page 21: Tema 1. Recursividad - us

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, 2

Análisis y Diseño de Algoritmos 41

2, 1 1, 1

1, 1 0, 0

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, 2 2, r6

Análisis y Diseño de Algoritmos 42

2, 1 1, 1

1, 1 0, 0

1, r7

Page 22: Tema 1. Recursividad - us

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, 2 2, r6

Análisis y Diseño de Algoritmos 43

2, 1 1, 1

1, 1 0, 0

1, 1

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, 2 2, r6

Análisis y Diseño de Algoritmos 44

2, 1 1, 1

1, 1 0, 0

1, 1 0, r8

Page 23: Tema 1. Recursividad - us

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, 2 2, r6

Análisis y Diseño de Algoritmos 45

2, 1 1, 1

1, 1 0, 0

1, 1 0, 0

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, r

3, 2 2, 1

Análisis y Diseño de Algoritmos 46

2, 1 1, 1

1, 1 0, 0

1, 1 0, 0

Page 24: Tema 1. Recursividad - us

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, 3

3, 2 2, 1

Análisis y Diseño de Algoritmos 47

2, 1 1, 1

1, 1 0, 0

1, 1 0, 0

Recursividad Múltiple

� Representación gráfica del cálculo de fib(4),

4, 3

3, 2 2, 1

sig1 sig2

Análisis y Diseño de Algoritmos 48

2, 1 1, 1

1, 1 0, 0

1, 1 0, 0

sig2sig1 sig2 sig1

sig2sig1

Page 25: Tema 1. Recursividad - us

Recursividad Múltiple

RecMultiple.h

typedef enum{false, true} logico;T2 f( T1 n);logico esCasoBase( T1 n);T2 solucionBase( T1 n);T1 sig1( T1 n);

Definición de tipos.

Declaración de prototipos.

Análisis y Diseño de Algoritmos 49

T1 sig1( T1 n);T1 sig2( T1 n);T2 combina( T1 n, T2 r1, T2 r2);

Para resolver un problema concreto, en el archivo “.h” T1 será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida.

prototipos.

Recursividad Múltiple

RecMultiple.c#include “RecMultiple.h”

// Esquema general para cualquier problema Rec Múlt iple (común)

T2 f( T1 n) { T2 r;if (esCasoBase(n)) {

r = solucionBase(n);}

Para resolver un problema concreto, en el archivo “.c” T1 será reemplazado por el tipo del

Análisis y Diseño de Algoritmos 50

}else {

T1 nSig1 = sig1(n);T2 r1 = f(nSig1);T1 nSig2 = sig2(n);T2 r2 = f(nSig2);r = combina(n, r1, r2);

}return r;

}

será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida.

Page 26: Tema 1. Recursividad - us

Recursividad MúltipleRecMultiple.c

// Métodos específicos para el problema a resolver

logico esCasoBase( T1 n) {

}

T2 solucionBase( T1 n) {

Para resolver un problema concreto, en el archivo “.c” T1 será reemplazado por el tipo del

Análisis y Diseño de Algoritmos 51

}

T1 sig1( T1 n) {

}

T1 sig2( T1 n) {

}

T2 combina( T1 n, T2 r1, T2 r2){

}

será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida. Además, se les dará código a los distintos métodos.

Recursividad Multiple

Principal.c#include <stdio.h>

#include “RecMultiple.h”

void main ( void ) {

T1 n;

Para resolver un problema concreto, en el archivo “.c” T1 será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida.

Análisis y Diseño de Algoritmos 52

T2 r;

printf (“Introduzca el valor para la entrada: ”);

scanf (“%efT1”, &n);

r = f (n);

printf (“El resultado de la función recursiva para la entrada %efT1 es %efT2”,n,r);

} Especificadores de formato: %c carácter %d int%ld long %f float%lf double %s cadena de carácteres

Page 27: Tema 1. Recursividad - us

Ejemplo Rec Múltiple: Fibonacci

Fibonacci.h

typedef enum{false, true} logico;int f (int n);logico esCasoBase (int n);int solucionBase (int n);int sig1 (int n);

Análisis y Diseño de Algoritmos 53

int sig1 (int n);int sig2 (int n);int combina (int n, int r1 , int r2 );

Ejemplo Rec Múltiple: Fibonacci

Fibonacci.c#include “Fibonacci.h”

// Esquema general para cualquier problema Rec Múlt iple (común)

int f (int n) {

int r;

if ( esCasoBase (n)) {

r = solucionBase (n);

Análisis y Diseño de Algoritmos 54

r = solucionBase (n);

}

else {

int nSig1 = sig1 (n);

int r1 = f (nSig1);

int nSig2 = sig2 (n);

int r2 = f (nSig2);

r = combina (n, r1, r2);

}

return r;

} …

Page 28: Tema 1. Recursividad - us

Ejemplo Rec Múltiple: FibonacciFibonacci.c

logico esCasoBase (int n) {

return (n == 0 || n == 1);

}

int solucionBase (int n) {

return n;

}

Análisis y Diseño de Algoritmos 55

}

int sig1 (int n) {

return n - 1;

}

int sig2 (int n) {

return n - 2;

}

int combina (int n, int r1 , int r2 ){

return r1 + r2;

}

Ejemplo Rec Múltiple: Fibonacci

Principal.c#include <stdio.h>

#include “Fibonacci.h”

void main (void) {

int n;

int

Análisis y Diseño de Algoritmos 56

int r;

printf ("Introduzca el valor para la entrada: ");

scanf ("%d", &n);

r = f (n);

printf ("El resultado de la funcion recursiva es %d",r);

}

Page 29: Tema 1. Recursividad - us

Ejemplo Rec Múltiple: Fibonacci

void main (void) {

int n;

int r;

printf ("Introduzca el valor para la entrada: ");

scanf ("%d", &n);

r = fibRec (n);

� Nuevamente, desplegando las funciones del esquemaobtenemos un único método que resuelve el problema.

Análisis y Diseño de Algoritmos 57

r = fibRec (n);

printf ("El resultado de la funcion recursiva es %d",r);

}

int fibRec (int n){

int r;

if (n == 0 || n == 1) {

r = n;

}

else {

r = fibRec (n-1) + fibRec (n-2);

}

return r;

}

5. Transformación Recursivo 5. Transformación Recursivo Iterativo

Análisis y Diseño de Algoritmos 58

Page 30: Tema 1. Recursividad - us

Transformación Recursivo-Iterativo

� Calcular iterativamente un valor definido de formarecursiva consiste en:� En el caso de la recursividad final, iterar hacia delante hasta

llegar al caso base.� En el caso de la recursividad no final, iterar dos veces, primero

hacia delante (hasta llegar al caso base y obtener el resultado

Análisis y Diseño de Algoritmos 59

hacia delante (hasta llegar al caso base y obtener el resultadobase) y después hacia atrás (combinando para obtener elresultado requerido).

Iteración Lineal Final

IterLinealFinal.h

typedef enum{false, true} logico;T2 f( T1 n);logico esCasoBase (T1 n);T2 solucionBase (T1 n);T1 siguiente (T1 n);

Definición de tipos.

Declaración de prototipos.

Análisis y Diseño de Algoritmos 60

T1 siguiente (T1 n);

Para resolver un problema concreto, en el archivo “.h” T1 será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida.

Page 31: Tema 1. Recursividad - us

Iteración Lineal Final

IterLinealFinal.c#include “IterLinealFinal.h”

// Esquema general para cualquier problema Iter Lin eal Final

T2 f( T1 n) {

T2 r;

while (! esCasoBase (n)) {

n = siguiente (n);

Para resolver un problema concreto, en el archivo “.c” T1 será reemplazado por el tipo del

Análisis y Diseño de Algoritmos 61

}

r = solucionBase (n);

return r;

}

será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida.

Iteración Lineal Final

IterLinealFinal.c…

// Métodos específicos para el problema a resolver

logico esCasoBase( T1 n) {

}

T2 solucionBase( T1 n) {

Para resolver un problema concreto, en el archivo “.c” T1 será reemplazado por el tipo del

Análisis y Diseño de Algoritmos 62

T2 solucionBase( T1 n) {

}

T1 siguiente( T1 n) {

}

será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida. Además, se les dará código a los distintos métodos.

Page 32: Tema 1. Recursividad - us

Iteración Lineal No Final

� En el caso de la recursividad no final, es necesariodefinir un método anterior mediante el cual se vayanrecuperando los problemas en el orden inverso al que sehan ido generando.

� El método anterior debe ser el inverso del métodosiguiente .

Análisis y Diseño de Algoritmos 63

siguiente .� A veces el inverso de una función matemática es muy

difícil de calcular e incluso imposible. Pero siempre esposible implementar adecuadamente el método anteriormediante una pila.

Iteración Lineal No Final

IterLinealNoFinal.h

typedef enum{false, true} logico;T2 f( T1 n);logico esCasoBase (T1 n);T2 solucionBase (T1 n);T1 siguiente (T1 n);

Definición de tipos.

Declaración de prototipos.

Análisis y Diseño de Algoritmos 64

T1 siguiente (T1 n); T1 anterior (T1 n); T2 combina (T1 n, T2 rSig );

Para resolver un problema concreto, en el archivo “.h” T1 será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida.

prototipos.

Page 33: Tema 1. Recursividad - us

Iteración Lineal No Final

IterLinealNoFinal.c#include “IterLinealNoFinal.h”

// Esquema general para cualquier problema Iter Lin eal No Final

T2 f( T1 n) { T1 nsig = n; // inicia();T2 r;while (! esCasoBase (nsig)) {

nsig = siguiente (nsig);

Para resolver un problema concreto, en el archivo “.c” T1 será reemplazado por el tipo del

Análisis y Diseño de Algoritmos 65

nsig = siguiente (nsig);}r = solucionBase (nsig); while (n != nsig) {

nsig = anterior (nsig); r = combina (nsig, r);

}return r;

}

será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida.

Iteración Lineal No Final

IterLinealNoFinal.c…

// Métodos específicos para el problema a resolver

logico esCasoBase( T1 n) {

}

T2 solucionBase( T1 n) {

Para resolver un problema concreto, en el archivo “.c” T1 será reemplazado por el tipo del

Análisis y Diseño de Algoritmos 66

}

T1 siguiente( T1 n) {

}

T1 anterior( T1 n) {

}

T2 combina( T1 n, T2 rSig){

}

será reemplazado por el tipo del parámetro de entrada, mientras T2 por el tipo del parámetro de salida. Además, se les dará código a los distintos métodos.

Page 34: Tema 1. Recursividad - us

Recursividad múltiple e Iteraciones

� No hay métodos para transformar la recursividad múltiple eniteración.

� Esto sí es posible en el caso de ecuaciones de recurrencia.Para ello, los casos bases deben estar claramenteidentificados, y ser independientes del problema de entrada.Ejemplos: Factorial, Fibonacci. Contraejemplo: MáximoEjemplos: Factorial, Fibonacci. Contraejemplo: MáximoComún Divisor.

� Se trata de ir acumulando en una o más variables losvalores adecuados, de forma que se vaya actualizando elestado del algoritmo.

� Inicialmente, es necesario inicializar correctamente lasvariables que forman parte del estado del algoritmo.

Análisis y Diseño de Algoritmos 67

Recursividad múltiple e Iteraciones

int fib( int n){

int a, b, a1, b1, n1;

if (n == 0 || n == 1) { return n; }

else {

n1 = 2;

a = 1; // Fib(n1)

b = 1; // Fib(n1 - 1)

Si es caso base, devuelve la solución para dicho valor .

Inicialización del estado.

Itera hasta que se alcanza while (n1 < n) {//Fin cuando n1 == n

a1 = a;

b1 = b;

a = a1 + b1;

b = a1;

n1 = n1 + 1;

}

}

return a; // a = Fib(n1) = Fib(n)

}

Análisis y Diseño de Algoritmos 68

Itera hasta que se alcanza el problema inicial.

Actualiza el estado combinando los valores.

Page 35: Tema 1. Recursividad - us

6. Ejercicios

Análisis y Diseño de Algoritmos 69

6. Ejercicios

Ejercicios

� Para resolver cualquier problema recursivo mediante lasdistintas propuestas estudiadas, es importante identificar:� Cuándo estamos ante un caso base� Cuál es la solución para los casos base� Transformación a realizar en los datos de entrada para� Transformación a realizar en los datos de entrada para

realizar la/s llamada/s recursiva/s (métodos siguiente, sig1,sig2).

� Combinación del resultado de la llamada recursiva juntocon los datos de entrada actuales (combina)

� Si es posible, el inverso a siguiente (anterior)

Análisis y Diseño de Algoritmos 70

Page 36: Tema 1. Recursividad - us

Ejercicios

1. Cálculo de la n-ésima potencia de un número

1

1 si 0

si 0n

n

nx

x x n−

== ⋅ >

Análisis y Diseño de Algoritmos 71

1 si 0nxx x n−= ⋅ >

Ejercicios

2. Potencia entera

2

1 si 0( , )

( , ) ( ( , / 2)) si 0

npot a n

cnd a n pot a n n

== ⋅ >

donde

Análisis y Diseño de Algoritmos 72

1 si es par ( , )

si es impar

ncnd a n

a n

=

donde

Page 37: Tema 1. Recursividad - us

Ejercicios

3. Suma Recursiva: A partir de un array de elementosenteros, calcular la suma de todos los componentesde dicho array.� El array “a” se puede declarar como variable global de forma

que no haya que pasarla como parámetro en cada llamada.

� El índice “i” indica los elementos del array que ya han sido

Análisis y Diseño de Algoritmos 73

� El índice “i” indica los elementos del array que ya han sidosumados, de forma que sum(i) devuelve la suma de loselementos desde a[0] hasta a[i].

[ ] si i 0( )

[ ] ( 1) si i > 0

a isum i

a i sum i

== + −

Ejercicios

4. Calcular una cadena con la representación en binario deun entero, donde + representa la concatenación decadenas:

"" si 0( )

nbinario n

==

Análisis y Diseño de Algoritmos 74

( )( / 2) ( ) si 0

binario nbinario n cnd n n

= + >

"0" si es par ( )

"1" si es impar

ncnd n

n

=

donde

Page 38: Tema 1. Recursividad - us

Ejercicios

5. Calcular una cadena con la representación en binario de un entero, donde + representa la concatenación de cadenas:

si 0( , )

w nbinario n w

== >

Análisis y Diseño de Algoritmos 75

( , )( / 2, ( , ) si 0

binario n wbinario n cnd n w n

= >

"0" si es par ( )

"1" si es impar

w ncnd n

w n

+= +

donde

Ejercicios

6. Algoritmo de Euclides para el cálculo del máximocomún divisor:

si 0( , )

( , mod ) si b 0

a bmcd a b

mcd b a b

== >

Análisis y Diseño de Algoritmos 76

( , mod ) si b 0mcd b a b >

Page 39: Tema 1. Recursividad - us

Ejercicios

7. Combinaciones sin repetición de n objetos tomados dek en k: nc(n,k)

nc(n,k) 1

0 si k > n

si k = 0 ó k = n

Análisis y Diseño de Algoritmos 77

nc(n,k) 1

nc(n – 1, k) + nc(n - 1, k - 1)

si k = 0 ó k = n

en otro caso

Ejercicios

8. Cálculo de los números de Fibonacci:

si 0 1( )

( 1) ( 2) si 1

n nfib n

fib n fib n n

≤ ≤= − + − >

Análisis y Diseño de Algoritmos 78

( 1) ( 2) si 1fib n fib n n − + − >