Download - Fundamentos de la programación 10 - UCM
10
GradoenIngenieríaInformáticaGradoenIngenieríadelSoftware
GradoenIngenieríadeComputadores
LuisHernándezYáñez
FacultaddeInformáticaUniversidadComplutense
Fundamentos de la programaciónLuis Hernández Yáñez
Fundamentos de la programación: Introducción a la recursión
Concepto de recursión 983Algoritmos recursivos 986
Funciones recursivas 987Diseño de funciones recursivas 989
Modelo de ejecución 990La pila del sistema 992La pila y las llamadas a función 994Ejecución de la función factorial() 1005
Tipos de recursión 1018Recursión simple 1019Recursión múltiple 1020Recursión anidada 1022Recursión cruzada 1026
Código del subprograma recursivo 1027Parámetros y recursión 1032Ejemplos de algoritmos recursivos 1034
Búsqueda binaria 1035Torres de Hanoi 1038
Recursión frente a iteración 1043Estructuras de datos recursivas 1045
Luis Hernández Yáñez
Página 983Fundamentos de la programación: Introducción a la recursión
Luis Hernández Yáñez
Página 984Fundamentos de la programación: Introducción a la recursión
Recursión(recursividad,recurrencia)Definiciónrecursiva:EnladefiniciónapareceloquesedefineFactorial(N)=Nx Factorial(N‐1) (N>=0)
(wikipedia.org)(wikipedia.org)
Laimagendelpaqueteaparecedentrodelpropiopaquete,...¡hastaelinfinito!
Laimagendelpaqueteaparecedentrodelpropiopaquete,...¡hastaelinfinito!
(wikipedia.org)(wikipedia.org)
Cadatriánguloestáformadoporotros
triángulosmáspequeños
Cadatriánguloestáformadoporotros
triángulosmáspequeños
Lacámaragrabaloquegraba(http://farm1.static.flickr.com/83/229219543_edf740535b.jpg)
Lacámaragrabaloquegraba(http://farm1.static.flickr.com/83/229219543_edf740535b.jpg)
Lasmatrioskas rusasLasmatrioskas rusas
Luis Hernández Yáñez
Página 985Fundamentos de la programación: Introducción a la recursión
Factorial(N)=Nx Factorial(N‐1)
Elfactorialsedefineenfuncióndesímismo
Losprogramasnopuedenmanejarlarecursióninfinita
Ladefiniciónrecursivadebeadjuntarunoomáscasosbase
Casobase:aquelenelquenoseutilizaladefiniciónrecursiva
Proporcionanpuntosfinalesdecálculo:
ElvalordeNsevaaproximandoalvalordelcasobase(0)
Nx Factorial(N‐1) siN>0 Casorecursivo(inducción)Factorial(N)
1 siN=0 Casobase(odeparada)
Luis Hernández Yáñez
Página 986Fundamentos de la programación: Introducción a la recursión
Luis Hernández Yáñez
Página 987Fundamentos de la programación: Introducción a la recursión
FuncionesrecursivasUnafunciónpuedeimplementarunalgoritmorecursivo
Lafunciónsellamaráasímismasinosehallegadoalcasobase
long long int factorial(int n) {long long int resultado;if (n == 0) { // Caso base
resultado = 1;}else {
resultado = n * factorial(n ‐ 1);}return resultado;
}
Nx Factorial(N‐1) siN>0Factorial(N)
1 siN=0
Luis Hernández Yáñez
Página 988Fundamentos de la programación: Introducción a la recursión
Funcionesrecursivaslong long int factorial(int n) {
long long int resultado;if (n == 0) { // Caso base
resultado = 1;}else {
resultado = n * factorial(n ‐ 1);}return resultado;
}
factorial(5) 5x factorial(4) 5x 4x factorial(3)
5x 4x 3x factorial(2) 5x 4x 3x 2x factorial(1)
5x 4x 3x 2x 1x factorial(0) 5x 4x 3x 2x 1x 1
120 CasobaseCasobase
factorial.cppfactorial.cpp
Luis Hernández Yáñez
Página 989Fundamentos de la programación: Introducción a la recursión
DiseñodefuncionesrecursivasUnafunciónrecursivadebesatisfacertrescondiciones:
Caso(s)base:Debehaberalmenosuncasobasedeparada
Inducción:Pasorecursivoqueprovocaunallamadarecursiva
Debesercorrectoparadistintosparámetrosdeentrada
Convergencia:Cadapasorecursivodebeacercarauncasobase
Sedescribeelproblemaentérminosdeproblemasmássencillos
Funciónfactorial():tienecasobase(N=0),siendocorrectaparaNescorrectaparaN+1(inducción)yseacercacadavezmásalcasobase(N‐1estámáscercade0queN)
Nx Factorial(N‐1) siN>0Factorial(N)
1 siN=0
Luis Hernández Yáñez
Página 990Fundamentos de la programación: Introducción a la recursión
Luis Hernández Yáñez
Página 991Fundamentos de la programación: Introducción a la recursión
long long int factorial(int n) {long long int resultado;if (n == 0) { // Caso base
resultado = 1;}else {
resultado = n * factorial(n ‐ 1);}return resultado;
}
Cadallamadarecursivafuerzaunanuevaejecucióndelafunción
Cadallamadautilizasuspropiosparámetrosporvaloryvariableslocales(n yresultado enestecaso)
Enlasllamadasalafunciónseutilizalapiladelsistemaparamantenerlosdatoslocalesyladireccióndevuelta
Luis Hernández Yáñez
Página 992Fundamentos de la programación: Introducción a la recursión
Regionesdememoriaquedistingueelsistemaoperativo:
Pila (Stack)
Montón (Heap)
Datos del programa
Código del programa
S.O.
LlamadasasubprogramasLlamadasasubprogramas
Memoriadinámica(Tema9)Memoriadinámica(Tema9)
MemoriaprincipalMemoriaprincipal
Luis Hernández Yáñez
Página 993Fundamentos de la programación: Introducción a la recursión
Mantienelosdatoslocalesdelafunciónyladireccióndevuelta
Estructuradetipopila:listaLIFO(last‐infirst‐out)
Elúltimoqueentraeselprimeroquesale:
Entra4
Entra4
4
Entra7
Entra7
7
4
Entra2
Entra2
2
7
4
Sale2
Sale2
7
4
Luis Hernández Yáñez
Página 994Fundamentos de la programación: Introducción a la recursión
Datoslocalesydireccionesdevuelta...int funcB(int x) {
...return x;
}
int funcA(int a) {int b;...b = funcB(a);... return b;
}
int main() {...cout << funcA(4);...
PilaPila<DIR1><DIR1>
<DIR2><DIR2>
Llamadaafunción:EntraladireccióndevueltaLlamadaafunción:Entraladireccióndevuelta
Luis Hernández Yáñez
Datoslocalesydireccionesdevuelta...int funcB(int x) {
...return x;
}
int funcA(int a) {int b;...b = funcB(a);... return b;
}
int main() {...cout << funcA(4);...
Página 995Fundamentos de la programación: Introducción a la recursión
<DIR1>
PilaPila<DIR1><DIR1>
<DIR2><DIR2>
Entradaenlafunción:SealojanlosdatoslocalesEntradaenlafunción:Sealojanlosdatoslocales
Luis Hernández Yáñez
Datoslocalesydireccionesdevuelta...int funcB(int x) {
...return x;
}
int funcA(int a) {int b;...b = funcB(a);... return b;
}
int main() {...cout << funcA(4);...
Página 996Fundamentos de la programación: Introducción a la recursión
b
a
<DIR1>
PilaPila<DIR1><DIR1>
<DIR2><DIR2> Llamadaafunción:EntraladireccióndevueltaLlamadaafunción:Entraladireccióndevuelta
Luis Hernández Yáñez
Datoslocalesydireccionesdevuelta...int funcB(int x) {
...return x;
}
int funcA(int a) {int b;...b = funcB(a);... return b;
}
int main() {...cout << funcA(4);...
Página 997Fundamentos de la programación: Introducción a la recursión
<DIR2>
b
a
<DIR1>
PilaPila<DIR1><DIR1>
<DIR2><DIR2>
Entradaenlafunción:SealojanlosdatoslocalesEntradaenlafunción:Sealojanlosdatoslocales
Luis Hernández Yáñez
Datoslocalesydireccionesdevuelta...int funcB(int x) {
...return x;
}
int funcA(int a) {int b;...b = funcB(a);... return b;
}
int main() {...cout << funcA(4);...
Página 998Fundamentos de la programación: Introducción a la recursión
x
<DIR2>
b
a
<DIR1>
PilaPila<DIR1><DIR1>
<DIR2><DIR2>
Vueltadelafunción:SeeliminanlosdatoslocalesVueltadelafunción:Seeliminanlosdatoslocales
Luis Hernández Yáñez
Datoslocalesydireccionesdevuelta...int funcB(int x) {
...return x;
}
int funcA(int a) {int b;...b = funcB(a);... return b;
}
int main() {...cout << funcA(4);...
Página 999Fundamentos de la programación: Introducción a la recursión
<DIR2>
b
a
<DIR1>
PilaPila<DIR1><DIR1>
<DIR2><DIR2>
Vueltadelafunción:SaleladireccióndevueltaVueltadelafunción:Saleladireccióndevuelta
Luis Hernández Yáñez
Datoslocalesydireccionesdevuelta...int funcB(int x) {
...return x;
}
int funcA(int a) {int b;...b = funcB(a);... return b;
}
int main() {...cout << funcA(4);...
Página 1000Fundamentos de la programación: Introducción a la recursión
b
a
<DIR1>
PilaPila<DIR1><DIR1>
<DIR2><DIR2> LaejecucióncontinúaenesadirecciónLaejecucióncontinúaenesadirección
Luis Hernández Yáñez
Datoslocalesydireccionesdevuelta...int funcB(int x) {
...return x;
}
int funcA(int a) {int b;...b = funcB(a);... return b;
}
int main() {...cout << funcA(4);...
Página 1001Fundamentos de la programación: Introducción a la recursión
b
a
<DIR1>
PilaPila<DIR1><DIR1>
<DIR2><DIR2>
Vueltadelafunción:SeeliminanlosdatoslocalesVueltadelafunción:Seeliminanlosdatoslocales
Luis Hernández Yáñez
Datoslocalesydireccionesdevuelta...int funcB(int x) {
...return x;
}
int funcA(int a) {int b;...b = funcB(a);... return b;
}
int main() {...cout << funcA(4);...
Página 1002Fundamentos de la programación: Introducción a la recursión
<DIR1>
PilaPila<DIR1><DIR1>
<DIR2><DIR2>
Vueltadelafunción:SaleladireccióndevueltaVueltadelafunción:Saleladireccióndevuelta
Luis Hernández Yáñez
Datoslocalesydireccionesdevuelta...int funcB(int x) {
...return x;
}
int funcA(int a) {int b;...b = funcB(a);... return b;
}
int main() {...cout << funcA(4);...
Página 1003Fundamentos de la programación: Introducción a la recursión
PilaPila<DIR1><DIR1>
<DIR2><DIR2>
LaejecucióncontinúaenesadirecciónLaejecucióncontinúaenesadirección
Luis Hernández Yáñez
Página 1004Fundamentos de la programación: Introducción a la recursión
Mecanismodepilaadecuadoparallamadasafuncionesanidadas:
Lasllamadasterminanenelordencontrarioacomosellaman...int funcC(...) {...
}
int funcB(...) {...... funcC(...)
}
int funcA(...) {...... funcB(...)
}
int main() {...cout << funcA(...);...
funcC
funcB
funcA
PilaPila
LLAMADAS
LLAMADASV
UELTAS
VUELTAS
Luis Hernández Yáñez
Página 1005Fundamentos de la programación: Introducción a la recursión
long long int factorial(int n) {long long int resultado;if (n == 0) { // Caso base
resultado = 1;}else {
resultado = n * factorial(n ‐ 1);}return resultado;
}
cout << factorial(5) << endl;
ObviaremoslasdireccionesdevueltaenlapilaObviaremoslasdireccionesdevueltaenlapila
Luis Hernández Yáñez
Página 1006Fundamentos de la programación: Introducción a la recursión
factorial(5)
resultado = ?
n = 5
PilaPila
Luis Hernández Yáñez
Página 1007Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
resultado = ?
n = 4
resultado = ?
n = 5
PilaPila
Luis Hernández Yáñez
Página 1008Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
factorial(3)
resultado = ?
n = 3
resultado = ?
n = 4
resultado = ?
n = 5
PilaPila
Luis Hernández Yáñez
Página 1009Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
factorial(3)
factorial(2)
resultado = ?
n = 2
resultado = ?
n = 3
resultado = ?
n = 4
resultado = ?
n = 5
PilaPila
Luis Hernández Yáñez
Página 1010Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
factorial(3)
factorial(2)
factorial(1)
resultado = ?
n = 1
resultado = ?
n = 2
resultado = ?
n = 3
resultado = ?
n = 4
resultado = ?
n = 5
PilaPila
Luis Hernández Yáñez
Página 1011Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
factorial(3)
factorial(2)
factorial(1)
factorial(0)
resultado = 1
n = 0
resultado = ?
n = 1
resultado = ?
n = 2
resultado = ?
n = 3
resultado = ?
n = 4
resultado = ?
n = 5
PilaPila
Luis Hernández Yáñez
Página 1012Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
factorial(3)
factorial(2)
factorial(1)
factorial(0) resultado = 1
n = 1
resultado = ?
n = 2
resultado = ?
n = 3
resultado = ?
n = 4
resultado = ?
n = 5
PilaPila
11
Luis Hernández Yáñez
Página 1013Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
factorial(3)
factorial(2)
factorial(1)
factorial(0)
resultado = 2
n = 2
resultado = ?
n = 3
resultado = ?
n = 4
resultado = ?
n = 5
PilaPila
11
11
Luis Hernández Yáñez
Página 1014Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
factorial(3)
factorial(2)
factorial(1)
factorial(0)
resultado = 6
n = 3
resultado = ?
n = 4
resultado = ?
n = 5
PilaPila
11
11
22
Luis Hernández Yáñez
Página 1015Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
factorial(3)
factorial(2)
factorial(1)
factorial(0)
resultado = 24
n = 4
resultado = ?
n = 5
PilaPila
11
11
22
66
Luis Hernández Yáñez
Página 1016Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
factorial(3)
factorial(2)
factorial(1)
factorial(0)
resultado = 120
n = 5
PilaPila
11
11
22
66
2424
Luis Hernández Yáñez
Página 1017Fundamentos de la programación: Introducción a la recursión
factorial(5)
factorial(4)
factorial(3)
factorial(2)
factorial(1)
factorial(0)
PilaPila120120
11
11
22
66
2424
Luis Hernández Yáñez
Página 1018Fundamentos de la programación: Introducción a la recursión
Luis Hernández Yáñez
Página 1019Fundamentos de la programación: Introducción a la recursión
Sólohayunallamadarecursiva
Ejemplo:Cálculodelfactorialdeunnúmeroenteropositivo
long long int factorial(int n) {long long int resultado;if (n == 0) { // Caso base
resultado = 1;}else {
resultado = n * factorial(n ‐ 1);}return resultado;
}UnasolallamadarecursivaUnasolallamadarecursiva
Luis Hernández Yáñez
Página 1020Fundamentos de la programación: Introducción a la recursión
Variasllamadasrecursivas
Ejemplo:CálculodelosnúmerosdeFibonacci
1 sin=1Fib(n)
0 sin=0
Fib(n‐1)+Fib(n‐2) sin>1
DosllamadasrecursivasDosllamadasrecursivas
Luis Hernández Yáñez
Página 1021Fundamentos de la programación: Introducción a la recursión
...int main() {
for (int i = 0; i < 20; i++) {cout << fibonacci(i) << endl;
}return 0;
}
int fibonacci(int n) {int resultado;if (n == 0) {
resultado = 0;}else if (n == 1) {
resultado = 1;}else {
resultado = fibonacci(n ‐ 1) + fibonacci(n ‐ 2);}return resultado;
}
1 sin=1Fib(n)
0 sin=0
Fib(n‐1)+Fib(n‐2) sin>1
fibonacci.cppfibonacci.cppLuis Hernández Yáñez
Página 1022Fundamentos de la programación: Introducción a la recursión
Enunallamadarecursivaalgunodelosargumentosesotrallamada
Ejemplo:CálculodelosnúmerosdeAckermann:
Ack(m‐1,1) sim>0yn=0Ack(m,n)
n+1 sim=0
Ack(m‐1,Ack(m,n‐1)) sim>0yn>0
ArgumentoqueesunallamadarecursivaArgumentoqueesunallamadarecursiva
Luis Hernández Yáñez
Página 1023Fundamentos de la programación: Introducción a la recursión
NúmerosdeAckermann...int ackermann(int m, int n) {
int resultado;if (m == 0) {
resultado = n + 1;}else if (n == 0) {
resultado = ackermann(m ‐ 1, 1);}else {
resultado = ackermann(m ‐ 1, ackermann(m, n ‐ 1));}return resultado;
}
Ack(m‐1,1) sim>0yn=0Ack(m,n)
n+1 sim=0
Ack(m‐1,Ack(m,n‐1)) sim>0yn>0
ackermann.cppackermann.cpp
Pruébaloconnúmerosmuybajos:
SegeneranMUCHASllamadasrecursivas
Pruébaloconnúmerosmuybajos:
SegeneranMUCHASllamadasrecursivas
Luis Hernández Yáñez
Página 1024Fundamentos de la programación: Introducción a la recursión
NúmerosdeAckermann
22
33
ackermann(1, 1)
ackermann(0, ackermann(1, 0))
ackermann(0, 1)
ackermann(0, 2)
Ack(m‐1,1) sim>0yn=0Ack(m,n)
n+1 sim=0
Ack(m‐1,Ack(m,n‐1)) sim>0yn>0
Luis Hernández Yáñez
Página 1025Fundamentos de la programación: Introducción a la recursión
NúmerosdeAckermann
33
55
4455
ackermann(2, 1)
ackermann(1, ackermann(2, 0))
ackermann(1, 1)
ackermann(1, 3)
ackermann(0, ackermann(1, 2))
ackermann(0, ackermann(1, 1))
ackermann(0, 3)
ackermann(0, 4)
2233
ackermann(0, ackermann(1, 0))
ackermann(0, 1)
ackermann(0, 2)
2233
ackermann(0, ackermann(1, 0))
ackermann(0, 1)
ackermann(0, 2)
Ack(m‐1,1) sim>0yn=0Ack(m,n)
n+1 sim=0
Ack(m‐1,Ack(m,n‐1)) sim>0yn>0
Luis Hernández Yáñez
Página 1026Fundamentos de la programación: Introducción a la recursión
Luis Hernández Yáñez
Página 1027Fundamentos de la programación: Introducción a la recursión
Códigoanterioryposterioralallamadarecursiva{
CódigoanteriorLlamadarecursivaCódigoposterior
}
Códigoanterior
Seejecutaparalasdistintasentradasantesqueelcódigoposterior
Códigoposterior
Seejecutaparalasdistintasentradastrasllegarsealcasobase
Elcódigoanteriorseejecutaenordendirectoparalasdistintasentradas,mientrasqueelcódigoposteriorlohaceenordeninverso
Sinohaycódigoanterior:recursiónpordelante
Sinohaycódigoposterior:recursiónpordetrás
Luis Hernández Yáñez
Página 1028Fundamentos de la programación: Introducción a la recursión
Códigoanterioryposterioralallamadarecursivavoid func(int n) {
if (n > 0) { // Caso base: n == 0cout << "Entrando (" << n << ")" << endl; // Código anteriorfunc(n ‐ 1); // Llamada recursivacout << "Saliendo (" << n << ")" << endl; // Código posterior
}}
func(5);
Elcódigoanteriorseejecutaparalossucesivosvaloresden(5,4,3,...)
Elcódigoposterioralrevés(1,2,3,...)
Luis Hernández Yáñez
Página 1029Fundamentos de la programación: Introducción a la recursión
Recorridodeloselementosdeunalista(directo)Elcódigoanterioralallamadaprocesalalistaensuorden:...void mostrar(tLista lista, int pos);
int main() {tLista lista;lista.cont = 0;// Carga del array...mostrar(lista, 0);
return 0;}
void mostrar(tLista lista, int pos) {if (pos < lista.cont) {
cout << lista.elementos[pos] << endl;mostrar(lista, pos + 1);
}}
directo.cppdirecto.cppLuis Hernández Yáñez
Página 1030Fundamentos de la programación: Introducción a la recursión
Recorridodeloselementosdeunalista(inverso)Elcódigoposteriorprocesalalistaenelordeninverso:...void mostrar(tLista lista, int pos);
int main() {tLista lista;lista.cont = 0;// Carga del array...mostrar(lista, 0);
return 0;}
void mostrar(tLista lista, int pos) {if (pos < lista.cont) {
mostrar(lista, pos + 1);cout << lista.elementos[pos] << endl;
}}
inverso.cppinverso.cpp
Luis Hernández Yáñez
Página 1031Fundamentos de la programación: Introducción a la recursión
Luis Hernández Yáñez
Página 1032Fundamentos de la programación: Introducción a la recursión
ParámetrosporvaloryporreferenciaParámetrosporvalor:cadallamadausalossuyospropios
Parámetrosporreferencia:mismavariableentodaslasllamadas
Recogenresultadosquetransmitenentrelasllamadas
void factorial(int n, int &fact) {if (n == 0) {
fact = 1;}else {
factorial(n ‐ 1, fact);fact = n * fact;
}}
Cuandon es0,elargumentodefact tomaelvalor1Alvolverselevamultiplicandoporlosdemásn (distintos)
Luis Hernández Yáñez
Página 1033Fundamentos de la programación: Introducción a la recursión
Luis Hernández Yáñez
Página 1034Fundamentos de la programación: Introducción a la recursión
Parteelproblemaensubproblemasmáspequeños
Aplicaelmismoprocesoacadasubproblema
Naturalezarecursiva(casosbase:encontradoonoquedalista)
Larepeticiónseconsigueconlasllamadasrecursivas
PartimosdelalistacompletaSinoquedalista...terminar(listavacía:noencontrado)Encasocontrario...ComprobarsielelementoenlamitadeselbuscadoSieselbuscado...terminar(encontrado)Sino...Sielbuscadoesmenorqueelelementomitad...Repetirconlaprimeramitaddelalista
Sielbuscadoesmayorqueelelementomitad...Repetirconlasegundamitaddelalista
PartimosdelalistacompletaSinoquedalista...terminar(listavacía:noencontrado)Encasocontrario...ComprobarsielelementoenlamitadeselbuscadoSieselbuscado...terminar(encontrado)Sino...Sielbuscadoesmenorqueelelementomitad...Repetirconlaprimeramitaddelalista
Sielbuscadoesmayorqueelelementomitad...Repetirconlasegundamitaddelalista
Luis Hernández Yáñez
Página 1035Fundamentos de la programación: Introducción a la recursión
Dosíndicesqueindiquenelinicioyelfinaldelasublista:
int buscar(tLista lista, int buscado, int ini, int fin)// Devuelve el índice (0, 1, ...) o ‐1 si no está
¿Cuálessonloscasosbase? Queyanoquedesublista(ini > fin) Noencontrado
Queseencuentreelelemento
RepasaenelTema7cómofuncionaycómoseimplementóiterativamentelabúsquedabinaria(compáralaconesta)RepasaenelTema7cómofuncionaycómoseimplementóiterativamentelabúsquedabinaria(compáralaconesta)
Luis Hernández Yáñez
Página 1036Fundamentos de la programación: Introducción a la recursión
int buscar(tLista lista, int buscado, int ini, int fin) {int pos = ‐1;if (ini <= fin) {
int mitad = (ini + fin) / 2;if (buscado == lista.elementos[mitad]) {
pos = mitad;}else if (buscado < lista.elementos[mitad]) {
pos = buscar(lista, buscado, ini, mitad ‐ 1);}else {
pos = buscar(lista, buscado, mitad + 1, fin);}
}return pos;
}
Llamada:pos = buscar(lista, valor, 0, lista.cont ‐ 1);
binaria.cppbinaria.cpp
Luis Hernández Yáñez
Página 1037Fundamentos de la programación: Introducción a la recursión
CuentaunaleyendaqueenuntemplodeHanoisedispusierontrespilaresdediamanteyenunodeellos64discosdeoro,dedistintostamañosycolocadosporordendetamañoconelmayordebajo
Cadamonje,ensuturno,debíamoverunúnicodiscodeunpilaraotro,paraconeltiempoconseguirentretodosllevarlatorredelpilarinicialaunodelosotrosdos;respetandounaúnicaregla:nuncaponerundiscosobreotrodemenortamaño
Cuandolohayanconseguido,¡seacabaráelmundo![Serequierenalmenos264‐1movimientos;sisehicieraunoporsegundo,seterminaríaenmásde500milmillonesdeaños]
Torredeochodiscos(wikipedia.org)Torredeochodiscos(wikipedia.org)
Luis Hernández Yáñez
Página 1038Fundamentos de la programación: Introducción a la recursión
Queremosresolvereljuego enelmenornúmerodepasosposible
¿Quédiscohayquemoverencadapasoyadónde?
Identifiquemosloselementos(torredecuatrodiscos):
Cadapilarseidentificaconunaletra
MoverdelpilarXalpilarY:
CogereldiscosuperiordeXyponerloencimadelosquehayaenY
AA BB CC
Luis Hernández Yáñez
Página 1039Fundamentos de la programación: Introducción a la recursión
Resolucióndelproblemaenbaseaproblemasmáspequeños
MoverNdiscosdelpilarAalpilarC:
MoverN‐1discosdelpilarAalpilarB
MovereldiscodelpilarAalpilarC
MoverN‐1discosdelpilarBalpilarC
ParallevarNdiscosdeunpilarorigen aotrodestino seusaeltercerocomoauxiliar
MoverN‐1discosdelorigen alauxiliar
Movereldiscodelorigen aldestino
MoverN‐1discosdelauxiliar aldestino
AA BB CC
AA BB CC
AA BB CC
AA BB CC
Mover4discosdeAa CMover4discosdeAa C
Luis Hernández Yáñez
Página 1040Fundamentos de la programación: Introducción a la recursión
MoverN‐1discossehaceigual,perousandoahoraotrosorigenydestino
MoverN‐1discosdelpilarAalpilarB:
MoverN‐2discosdelpilarAalpilarC
MovereldiscodelpilarAalpilarB
MoverN‐2discosdelpilarCalpilarB
Naturalezarecursivadelasolución
AA BB CC
AA BB CC
AA BB CC
AA BB CCSimulaciónpara4discos(wikipedia.org)Simulaciónpara4discos(wikipedia.org)
Mover3discosdeAa BMover3discosdeAa B
Luis Hernández Yáñez
Página 1041Fundamentos de la programación: Introducción a la recursión
Casobase:noquedandiscosquemover...void hanoi(int n, char origen, char destino, char auxiliar) {
if (n > 0) {hanoi(n ‐ 1, origen, auxiliar, destino);cout << origen << " ‐‐> " << destino << endl;hanoi(n ‐ 1, auxiliar, destino, origen);
}}
int main() {int n;cout << "Número de torres: ";cin >> n;hanoi(n, 'A', 'C', 'B');
return 0;}
hanoi.cpphanoi.cppLuis Hernández Yáñez
Página 1042Fundamentos de la programación: Introducción a la recursión
Luis Hernández Yáñez
Página 1043Fundamentos de la programación: Introducción a la recursión
long long int factorial(int n) {long long int fact;
assert(n >= 0);
if (n == 0) {fact = 1;
}else {
fact = n * factorial(n ‐ 1);}
return fact;}
long long int factorial(int n) {long long int fact = 1;
assert(n >= 0);
for (int i = 1; i <= n; i++) {fact = fact * i;
}
return fact;}
Luis Hernández Yáñez
Página 1044Fundamentos de la programación: Introducción a la recursión
¿Quéespreferible?Cualquieralgoritmorecursivotieneunoiterativoequivalente
Losrecursivossonmenoseficientesquelositerativos:
Sobrecargadelasllamadasasubprograma
Sihayunaversióniterativasencilla,serápreferiblealarecursiva
Enocasioneslaversiónrecursivaesmuchomássimple
Serápreferiblesinohayrequisitosderendimiento
ComparalasversionesrecursivasdelfactorialodelosnúmerosdeFibonacciconsusequivalentesiterativas
¿YquétalunaversióniterativaparalosnúmerosdeAckermann?
Luis Hernández Yáñez
Página 1045Fundamentos de la programación: Introducción a la recursión
Luis Hernández Yáñez
Página 1046Fundamentos de la programación: Introducción a la recursión
DefiniciónrecursivadelistasYahemosdefinidodeformarecursivaalgunaestructuradedatos:
Laslistassonsecuencias:
Lalista1,2,3consisteenelelemento1seguidodelalista2,3,que,asuvez,consisteenelelemento2seguidodelalista3,que,asuvez,consisteenelelemento3seguidodelalistavacía(casobase)
Hayotrasestructurasconnaturalezarecursiva(p.e.,losárboles)queestudiarásenposteriorescursos
secuenciavacía(ningúnelemento)
elementoseguidodeunasecuenciaSecuencia
listavacía(ningúnelemento) (Casobase)
elementoseguidodeunalistaLista
Luis Hernández Yáñez
Página 1047Fundamentos de la programación: Introducción a la recursión
ProcesamientodeestructurasdedatosrecursivasNaturalezarecursivadelasestructuras:procesamientorecursivo
Procesar(lista):
Silistanovacía(casobase):
Procesarelprimerelementodelalista//Códigoanterior
Procesar(resto(lista))
Procesarelprimerelementodelalista//Códigoposterior
resto(lista):sublistatrasquitarelprimerelemento
Luis Hernández Yáñez
LicenciaCC(Creative Commons)Estetipodelicenciasofrecenalgunosderechosaterceraspersonasbajociertascondiciones.
Estedocumentotieneestablecidaslassiguientes:
Pulsaenlaimagendearribaaladerechaparasabermás.
Fundamentos de la programación: Introducción a la recursión Página 1048
Reconocimiento(Attribution):Encualquierexplotacióndelaobraautorizadaporlalicenciaharáfaltareconocerlaautoría.
Nocomercial(Noncommercial):Laexplotacióndelaobraquedalimitadaausosnocomerciales.
Compartirigual(Sharealike):Laexplotaciónautorizadaincluyelacreacióndeobrasderivadassiemprequemantenganlamismalicenciaalserdivulgadas.
Fundamentos de la programación Ejercicios del Tema 10 — Pág. 1
Facultad de Informática – Universidad Complutense
Fundamentos de la programación Curso 2013–2014
HojadeejerciciosdelTema10
1. Escribeunsubprogramarecursivoquerecibaunnúmeroenteropositivon1ymuestresuscifrasenordeninversoenlapantalla.PorEjemplo:
Número:1234 Alrevés:4321
2. Escribeunsubprogramarecursivoquerecibaunnúmeroenteropositivon1ydevuelvasunúmerodedígitos.
3. Escribe una función recursiva invierte() que acepte caracteres por tecladohasta recibir un INTRO y los imprima en orden inverso al de lectura. Loscaracteres se leerán uno a uno y no deben almacenarse en un array; bastaemplearunasolavariablelocalalafuncióninvierte()detipochar.
4. Escribeunafunciónrecursivaquedigasiunacadenacontieneunpalíndromo.
5. Escribe una función recursiva pascal(i,j) que calcule el elemento i, j delTriángulodePascal(odeTartaglia),quesigueelsiguientepatrón:loselementosenelbordedel triángulosonunosyel restode loselementos son igualesa lasumadelosdoselementosquehaysobreellos:
1 1 1
1 2 1 1 3 3 1
1 4 6 4 1 1 5 10 10 5 1
1 6 15 20 15 6 1 ...
6. Unamanera de expresar la potencia esmediante la definición recurrente quesigue:
Dados x, un número real, y n 0, un entero positivo, escribe una funciónrecursiva potRec2() que calcule la potencia de acuerdo con esa definición ypruébalaenunprogramaprincipal.
imparesnynsixx
paresnynsixx
nsi
xn
n n
0
0*
01
1
2
Fundamentos de la programación Ejercicios del Tema 10 — Pág. 2
7. Dadoelsiguientesubprogramarecursivo:
void f(long long int num, long long int div) { if (num >= div) { if ((num % div) == 0) { cout << div << endl; f(num / div, div); } else { f(num, div + 1); } } }
a) Dadounenterocualquierax,¿quémuestralallamadaf(x, 2)?¿Cuálseríaunnombremásadecuadoparalafunciónf()?
b) Implementaunaversióniterativaequivalente.
8. EnunprogramaenC++nosprohíbenutilizarlasinstruccionesdo‐whileyfor.¿Cómoreescribiríaslossiguientesfragmentos?
do { Instrucción1; Instrucción2; } while condicion;
for(int i = 1; i <= n; i++) { Instrucción1; Instrucción2; }
9. Elproblemadeljeep:Enunoasisdeldesiertoseencuentraunafurgonetayjuntoa ella hay N bidones de gasolina. En el depósito de la furgoneta cabeexactamenteunbidónylafurgonetasólopuedetransportarunbidóncadavez.Además, sólo se puede llenar el depósito cuando éste esté vacío. Con cadadepósito(unbidón)lafurgonetapuederecorrerunadistanciaA(enkilómetros).
Escribe un subprograma recursivo que tome como entrada el número debidonesquetenemosydevuelvaladistanciamáximaquepodemosrecorrerconlafurgoneta(enkilómetros).
Pista: ¿Qué distancia podemos recorrer para transportar N–1 bidones lo máslejosposibleconexactamenteunbidóneneldepósito?
(Depósito)
Distancia D
Fundamentos de la programación Ejercicios del Tema 10 — Pág. 3
10. Dadalassiguientesdeclaraciones:
int const N = 100; typedef int tTabla[N];
Escribesubprogramasrecursivospara:
a) CalcularelvalormáximodeloselementosdeunatabladetipotTabla.
b) CalcularlamediadeloselementosdeunatabladetipotTabla.
c) ComprobarsitodosloselementosdeunatabladetipotTablasoniguales.
d) ComprobarsiestánordenadosloselementosdeunatabladetipotTabla.
e) ContarelnúmerodeocurrenciasdeunvalorenlatabladetipotTabla.
11. Elproblemade lasochoreinas: Sequiere colocarocho reinasenun tablerodeajedrezdeformaqueningunadeellascomaaalgunaotra.Obviamente,cadaunaestaráenunafiladistinta:
Debes desarrollar un programa que obtenga una posible distribución de lasreinas que sea una solución correcta. Para hacerlo, busca, para cada fila, unaposiciónposibledelasiguientereinaqueseasegura(nolecomeningunareinaanterior). Si no es posible, se volverá a la reina anterior para probar otrasposicionesposibles.Si seconsiguecolocar laoctavareina,sehabráresueltoelproblema.
bool colocar(tTablero &tablero, int reina);
Elsubprogramaintentarácolocaresenúmerodereinaenlafilareinasinquelecoman.Siloconsigue,haráunallamadarecursivaparaqueseintentecolocarla siguiente reina (reina + 1). Si se consigue colocar la octava, terminarádevolviendotrue.Sinoseconsigue,devolveráfalse.
Bastaguardarlacolumnadecadareina(siempreestaránenfilasdistintas).
¿Cuándosecomenentresídosreinas?
0 1 2 3 0 1 2 3 0 1 2 30 R 0 R 0 R 1 1 1 2 2 2 R3 R 3 R 3
Osea:oestánenlamismacolumna,otienenigualdiferencia,envalorabsoluto,entrelasfilasylascolumnas(|3–0|=3,|0–3|=3o|2–0|=2,|3–1|=2).
Puedesintentarotraversiónquemuestretodaslasposiblessoluciones.
Misma columna Igual diferencia entre filas y entre columnas:
3 - 0 y 0 - 3
Igual diferencia entre filas y entre columnas:
2 – 0 y 3 - 1