Universidad Carlos III de Madrid

Ingeniería de Telecomunicación

Enero-Mayo 2010 / January-May 2010

Recursión

Objectives Section Objetivos de aprendizaje

Objetivos de aprendizaje para Recursión

  • Definir el concepto de recursión (Bloom 1*)

  • Describir la secuencia de computaciones que se llevan a cabo al evaluar un método recursivo (Bloom 2*)

  • Convertir un método recursivo por la cola a forma iterativa (Bloom 3*)

  • Clasificar un método recursivo a uno de los tipos de recursión estudiados (Bloom 3*)

  • Dado un método recursivo, encontrar el dominio de convergencia para casos sencillos (Bloom 4)

  • Escribir un método recursivo dado un problema a resolver (Bloom 5)

  • Comparar diferentes métodos recursivos que resuelven el mismo problema (Bloom 6)

Lecture Section Sesión 1 (teoría): Recursión

Material

Lab Section Sesión 2 (laboratorio): Recursión

Material

Material (con soluciones)

Learning Pills Section Píldoras de aprendizaje

¿SABÍAS QUE...?

El siguiente código que permite calcular la serie armónica es erróneo y provocará una excepción de tipo StackOverflowError :

public double h(int n) {
  return h(n-1) + 1.0/n;
} 
					

¿SABÍAS QUE...?

El método recursivo, aún con el caso base que se muestra, seguirá provocando una excepción de tipo StackOverflowError:

public double h(int n) {
 if (n==1) return 1.0;
 return h(n-1) + 1.0/n;
}						
					

¿SABÍAS QUE...?

La recursión por la cola se puede convertir de forma inmediata en iteración. Cuando existe una llamada recursiva en un método y que es la última instrucción del mismo, el método se puede convertir automáticamente en iterativo. El siguiente método tiene su versión iterativa.

public void torresHanoi(int n,char de,char to,char ch){
 if (n==1)
  System.out.println("Mover 1 de"+de+"hacia"+to);
 else
  if (n>1) {
   torresHanoi(n-1, de, ch, to);
   System.out.println("Mover "+n+"de"+de+"hacia"+ to);
   torresHanoi(n-1, ch,to, de);
}}

¿SABÍAS QUE...?

A veces la recursión no es eficiente. Por ejemplo, la serie de los números de Fibonacci se puede calcular mediante el siguiente método recursivo. Sin embargo, el tiempo que tarda dicho método crece de de forma exponencial con n, lo que hace que sea inútil el cálculo salvo para valores pequeños de n.

public static long fib(int n) {
 if (n <= 1) 
  return n;
 else 
  return fib(n-1) + fib(n-2);
 }
siendo fib(0) = 0 y fib(1) = 1

¿SABÍAS QUE...?

Se puede optimizar el anterior algoritmo recursivo no lineal para el cálculo de la serie de Fibonnaci por otro de recursividad lineal que permite hacerlo más eficiente.

¿SABÍAS QUE...?

En general, si se dispone de un algoritmo recursivo y otro iterativo para resolver un problema, se suele preferir el iterativo por razones de eficiencia.

¿SABÍAS QUE...?

Un algoritmo de ordenamiento, como puede ser el "QuickSort" de orden logarítmico O(n·log n), siempre es más rápido que otro de orden cuadrático O(n^2) como el "BubbleSort" cuando n se hace muy grande.

¿SABÍAS QUE...?

Si vamos a trabajar con tamaños de datos pequeños (valores bajos de n), el orden de complejidad del algoritmo recursivo no es significativo y puede, incluso, llegar a ser un problema.

¿SABÍAS QUE...?

En función del tamaño (n) del conjunto de datos que manipula un algoritmo, aumenta la evolución del coste temporal del mismo en base a los órdenes crecientes de complejidad y de las constantes multiplicativas.

¿SABÍAS QUE...?

Los algoritmos de Backtracking suelen resolverse de forma recursiva.

¿SABÍAS QUE...?

Puedes verificar si has programado correctamente un método recursivo contestando a tres preguntas sobre el caso base y los casos recursivos respectivamente.

¿SABÍAS QUE...?

La tecnica de diseño de algoritmos llamada "divide y vencerás" usando recursividad permite, aplicada al algoritmo de ordenación "QuickSort", conseguir disminuir su tiempo promedio de ejecución hasta ser de orden logarítmico O(log n).

¿SABÍAS QUE...?

La "programación dinámica" permite resolver sub-problemas generados por un planteamiento recursivo de forma no recursiva, guardando los valores de las soluciones en una tabla.

¿SABÍAS QUE...?

La complejidad de este fragmento de código es O(n^2)

for (int i = 0; i < n; i++) {
 for (int k = 0; k < i; i++) {
  m[i][k] = a[i] * a[k]
 }
}