recursión como herramienta en resolución de problemas ... · ejemplo matemática no trivial lo! t...
TRANSCRIPT
Recursión como herramienta en resolución
de problemas computacionales
Modularidad
! Es común dividir los algoritmos en módulos
! Cada módulo lleva a cabo cierta funcionalidad
! Muchas veces los módulos sirven para más de un algoritmo, o sea, se reutilizan
! Gente publica bibliotecas de tales módulos, que llamamos “librerías” por anglismo
! El módulo más pequeño es una subrutina
Subrutinas! Métodos auxiliares
! Toman uno o varios parámetros de tipos predefinidos
! Ejecutan su propio código a base de los parámetros recibidos
! Al recibir punteros, pueden modificar variables de la parte del programa que llamó a la subrutina
! Producen (opcionalmente) un valor de salida
Ejemplos
! Frecuentemente usamos subrutinas de las bibliotecas estándares de ANSI-C para la siguiente funcionalidad
! Impresión en el terminal (stdio.h)
! Lectura de datos del teclado (stdio.h)
! Operaciones matemáticas (math.h)
! Manipulación de cadenas de caracteres (string.h)
Encadenados
! El método principal (main) puede llamar a subrutinas
! Luego, esas subrutinas pueden llamar a otras subrutinas
! Esas luego a otras
! Etcétera - no hay un límite fijo de “profundidad” de llamadas
Flujo de control
! Típicamente solamente una (sub)rutina de un programa específico puede estar en ejecución a la vez
! La ejecución simultánea de dos o más (sub)rutinas requiere programación paralela y múltiples núcleos y/o procesadores
! Se dice que la (sub)rutina en ejecución “tiene control” de la computadora
! Al terminar su ejecución, una subrutina devuelve el control de la computadora a la rutina que la llamó
Código en ANSI-C
#include <stdio.h> // biblioteca que incluye la rutina printf#include “pidevalor.h” // subrutina externa “nuestra”int computo(int v) { return (v % 2);}int main(int c, char** s) { // rutina principal int valor = pidevalor(5, 10); // llamada a subrutina printf(“%d\n”, computo(valor)); // llamadas a otras dos return 1; // salir del programa}
La implementación de pidevalor está en la página de asesorías
Ejecución del ejemplo
main pidevalor
computo printf
Iteración! A veces es necesario realizar alguna computación de
manera repetida como componente del algoritmo
! Este código estará o adentro de un ciclo tal como es o se puede “vestir” como una subrutina
! Llamas repetidas de una subrutina o la ejecución de un bloque de código en un ciclo se conoce como iteración
! Ya lo usábamos en clase por ejemplo para generar potencias de dos y los números de Fibonacci
Números primos revisitadosrutina_principal { entero positivo n = valor de entrada; entero positivo i = 3; si (n % 2 == 0 y n > 2) { imprimir “no es primo”; salir del programa; } mientras (i < raiz_cuadrada(n)) { si (n % i == 0) { imprimir “ no es primo,”; salir del programa; } i += 2; } imprimir “resulta que es primo”; salir del programa;}
Caso especial
Iteración
Recursión
! Cuando una (sub)rutina llama a si misma, se dice que es recursivo
! Intentamos, por fines de ejemplo, esto para el caso de los números primos
! Vamos a ver muchos algoritmos recursivos en la segunda mitad de esta unidad de aprendizaje
Primos recursivos
primo(entero numero, entrada divisor) { si (divisor == 1) { devolver “verdad”; } en otro caso si (numero % divisor == 0) { devolver “falso”; } en otro caso { devolver primo(numero, divisor - 2); }}rutina_principal { si (primo(entrada, raiz_cuadrada(entrada)) { imprimir “resulta que es primo”; } en otro caso { imprimir “no es primo”; } salir del programa;}
Llamada recursiva
Rutina recursiva
Rutina principal
Análisis asintótico revisitado
Algoritmos simples
Para analizar desde un pseudocódigo la complejidad,típicamente se aplica las reglas siguientes:
Asignación de variables simples toman tiempo O (1).Escribir una salida simple toma tiempo O (1).Leer una entrada simple toma tiempo O (1).
Algoritmos recursivos– p. 2
! Asignación de una variable toma tiempo constante
! Llamada a una rutina toma tiempo constante, y luego hay que tomar en cuenta los pasos que conlleva
! Escribir una salida y leer una entrada simple ambos toman tiempo constante
Análisis de algoritmos recursivos
! Típicamente hay que escribir una ecuación recursiva para poder correctamente caracterizar la cantidad de llamadas que se hará a la rutina recursiva
! Esto suele involucrar más matemáticas de lo que podemos acomodar en esta unidad de aprendizaje
! Vamos a ver algunos ejemplos sin meternos en cómo fueron resueltos
Ejemplo
Aplicación iterativa
Otra opcion es aplicar la ecuación recursiva de unamanera iterativa.Por ejemplo, con la ecuación diferencial
!
T (1) = c1,T (n) ! 2T
"n2
#
+ c2n.
obtenemos por aplicación repetida
T (n) ! 2T"
n2
#
+ c2n ! 2"
2T (n/4) + c2n2
#
+ c2n= 4T (n/4) + 2c2n ! 4 (2T (n/8) + c2n/4) + 2c2n= 8T (n/8) + 3c2n.
Algoritmos recursivos– p. 9
El resultado
De la condición 2k = n sabemos que
k = log n.
Entonces, con T (1) ! c1 obtenemos
T (n) ! c1n + c2n log n
o seaT (n) " O (n log n) .
Algoritmos recursivos– p. 11
Matemática no trivial
Ejemplo
Matemática no trivial
Estimación
Incluso se puede estimar la parte heterogénica en algunoscasos donde d no es multiplicativa.Por ejemplo, en
!
T (1) = 1T (n) = 3T
"n2
#
+ 2n1,5
d(n) = 2n1,5 no es multiplicativa, mientras n1,5 sóla lo es.
Algoritmos recursivos– p. 21
Análisis del ejemplo
Si tuvieramos que U(1) = 1, tendríamos una partehomogénica 3log n = nlog 3.En el caso U(1) = 1
2 tendríamos12n
log 3.En la parte heterogénica, el valor de U(1) no tiene ningúnefecto.=! a = 3 y b = 2=! d(b) = b1,5 " 2, 82=! d(b) < a=! La parte heterogénica es O
!
nlog 3"
.=! U(n) # O
!
nlog 3"
Con T (n) = 2U(n) =! T (n) # O!
nlog 3"
Algoritmos recursivos– p. 23
Ejemplo
Matemática no trivial
Otro ejemplo
!
T (1) = 1T (n) = 2T
"n2
#
+ n log n
donde la parte homogénica es ak = 2log n = nlog 2 = n.
Algoritmos recursivos– p. 24
Asignación k = log n
2k!1k(k + 1) = 2log n!1 log n(log n + 1)
= 2log(n
2 )(log2 n + log n)= n
2 (log2 n + log n),
=! La parte heterogénica es O!
n log2 n"
.
Algoritmos recursivos– p. 26
Ejemplo
Matemática casi trivial pero larga
Método de expansión
Elmetodo de expansion facilita la computacióninvolucrada en abrir una ecuación recursiva.Ejemplo:
!
R(1) = 1R(n) = 2R(n ! 1) + n, donde n " 2.
Algoritmos recursivos– p. 27
Multiplicar y sumar
Multiplicamos por los coeficientes del lado izquiera y sumamos:R(n) = 2n!1R(1) + n + 2(n ! 1) + 4(n ! 2) + . . . + 2n!22= n + 2(n ! 1) + 4(n ! 2) + . . . + 2n!22 + 2n!1
=n!1!
i=0
2i(n ! i)
= 20 + . . . + 20" #$ %
n veces
+21 + . . . + 21" #$ %
n!1 veces
+22 + . . . + 22" #$ %
n!2 veces
+ . . . + 2n!1"#$%
1 vez
=n!1!
i=0
i!
j=0
2j =n!1!
i=0
(2i+1 ! 1) =n!1!
i=0
2i+1 !n!1!
i=0
1
= 2n+1 ! 2 ! n.
Algoritmos recursivos– p. 30
Método experimental
! Ustedes, en vez de analizar de esta manera, pueden estudiar experimentalmente la curva de tamaño de instancia versus número de pasos (igual como en el segundo proyecto)
! Luego ven visualmente desde su forma a cuál función de complejidad típica se acerca o que por lo menos esté acotado de manera asintótica