¿Cuál es la diferencia entre la recursión normal y la recursiva de la cola con ejemplos?

La recursión de cola es un subconjunto de recursión donde el valor devuelto se obtiene a través de una llamada de cola, es decir, lo último que hace una función es llamar a otra función.

Compare estos dos ejemplos:

public int factorial (int n) {
if (n <= 1) devuelve 1;
retorno n * factorial (n – 1);
}

Esto no es una llamada de cola, porque el resultado del factorial se multiplica por algo, la llamada a la función no es la última operación.

public int factorial (int n) {
return tailFactorial (1, n);
}

private int tailFactorial (int acumulador, int n) {
si (n <= 1) devuelve el acumulador;
return tailFactorial (acumulador * n, n – 1);
}

Esta es una llamada de cola, porque el resultado de factorial se devuelve inmediatamente.

Entonces, ahora la pregunta es, ¿por qué molestarse? Y la respuesta es la optimización de llamada de cola: si la última acción de un método es una llamada a otro método, en lugar de crear un nuevo marco de pila para el contexto del nuevo método (argumentos, variables locales, etc.), podemos reemplazar El actual . Uno de los inconvenientes de los métodos recursivos normales es que son realmente abusivos para la pila de llamadas. La optimización de llamadas de cola elimina este problema y garantiza que el rendimiento de un algoritmo recursivo es exactamente tan bueno como su contraparte iterativa (aunque potencialmente es mucho más legible).

Es posible que desee dar un vistazo a Tail call – Wikipedia.

Recursión de la cola:

La función recursiva es recursiva de cola si la última llamada ejecutada por la función es recursiva . es decir, no hay nada que hacer en la fase de desenrollamiento de recursión.

Ventajas de la recursión de la cola sobre la recursividad normal:

  1. Las llamadas recursivas de cola se pueden implementar sin agregar un nuevo marco de pila a la pila de llamadas. La mayor parte del marco del procedimiento actual ya no es necesario y puede reemplazarse por el marco de la siguiente llamada recursiva de cola, modificada según corresponda.
  2. En este caso, en lugar de asignar un marco de pila para cada llamada, el compilador puede volver a trabajar el código para simplemente reutilizar el marco de pila actual, lo que significa que una función recursiva de cola solo usará un solo marco de pila en lugar de cientos o incluso miles.
  3. La cola recursiva es mejor que la no recursiva, ya que los compiladores modernos pueden optimizar la recursividad de la cola. El compilador moderno básicamente elimina las llamadas de cola para optimizar el código recursivo de cola. Esta optimización es posible porque el compilador sabe que una vez que se realiza la llamada recursiva de cola, no se necesitarán copias previas de variables, ya que no hay más código para ejecutar.
  4. Tail Call Elimination es el proceso en el que algunos compiladores convierten el código recursivo de cola en su versión iterativa equivalente o en una versión no recursiva equivalente utilizando saltos como goto.
  5. En lenguajes de programación funcionales, la eliminación de llamadas de cola a menudo está garantizada por el estándar de lenguaje, lo que permite que la recursión de cola use una cantidad similar de memoria como un bucle equivalente.
  6. Vea el ejemplo a continuación, la primera función es recursiva y la segunda función es recursiva de cola. (Código Scala)

objeto factorial
{
def main (args: Array [String])
{
val a = 5;
val b = 6;

println (“Factorial de” + a + “=>” + factorialRecursive (a));

println (“Factorial de” + b + “=>” + factorialTailRecusrive (b));
}

def factorialRecursive (n: Int): Int =
{
si (n <= 1)
retorno 1;
más
return n * factorialRecursive (n – 1);
}

def factorialTailRecusrive (n: Int, resultado: Int = 1): Int =
{
si (n <= 1)
resultado de retorno;
más
factorialTailRecusrive (n – 1, n * resultado)
}
}

Agrego algunos más:

No pasa por valor (copia) cuando la llamada de cola es infinitamente recursiva * (espacio limitado).

También (Ver: la respuesta de Hans Hyttel a ¿Desenrollar la recursión de la cola elimina la necesidad de una pila?)

En caso de recursión de cola, no se necesitan enlaces intermedios, ya que cada llamada recursiva ocurre cuando la persona que llama termina.

Por lo tanto, en un lenguaje de programación que solo utiliza la recursividad de cola, no es necesario un tipo de implementación basado en pila.

Respuesta del usuario de PS Quora a ¿Cómo pueden ser recursivas las enumeraciones en Swift?

* En una nota no relacionada, el poco conocimiento o incluso la aplicación descuidada de algos básicos, tipos, conceptos básicos del lenguaje pueden darle una ilusión de recursión infinita, cuando no la hay. Ver la respuesta de Vladislav Zorov a En términos simples, ¿por qué la recursión utilizada en el cálculo de raíces irracionales es infinitamente profunda?

More Interesting

¿Cuál es la diferencia entre un algoritmo genético y el recocido simulado?

¿Qué es Algoritmo, Diagrama de flujo y Pseudocódigo en la planificación de programas antes de escribir?

¿Los algoritmos están sesgados inherentemente hacia las opiniones subjetivas de sus creadores humanos?

¿Qué estrategia emplearías para vencer a un algoritmo de computadora jugando póquer matemáticamente perfecto?

Cómo comenzar a hacer mi propia solución de divide y vencerás

¿Hay algún modelo físico o fenómeno que permita resolver rápidamente los problemas NP-hard?

¿Es 'Cracking the Coding Interview' una lectura obligatoria cuando se postula para ser un ingeniero front-end?

Cómo reducir los componentes fuertemente conectados en nodos únicos de manera eficiente si estoy usando una representación de lista de adyacencia

¿Cuáles son las principales diferencias en términos de definición / idea clave, dominio de aplicación y eficiencia entre árboles de segmento, árboles de intervalo, árboles indexados binarios y árboles de rango?

Cómo resolver la ordenación rápida utilizando un método no recursivo

¿Qué estrategias o algoritmos se utilizan para agrupar rutas de pasajeros en función de la ubicación y la hora de salida?

¿Ha habido algún trabajo teórico que delinee qué clase de algoritmos pueden y no pueden mapearse para mapear / reducir?

¿Cuál es el orden cronológico de los algoritmos de reconocimiento facial?

¿Cómo construir un algoritmo hash? ¿Dónde puedo aprender más?

¿Cómo Thomas Cormen y sus coautores generaron el índice para su libro clásico de algoritmos?