En programación, se conoce como recursividad a la capacidad que tiene una función para llamarse a sí misma, con el propósito de resolver un problema dividiéndolo en subproblemas más pequeños, obteniendo así una solución al alcanzar el caso base. A diferencia de un bucle, una función recursiva no está basada en una declaración condicional iterativa sino en la llamada repetitiva de sí misma.
Las funciones recursivas suelen utilizarse para resolver problemas de naturaleza recursiva, que serían más difíciles o menos adecuados de abordar que con enfoques iterativos, como por ejemplo, los algoritmos de búsqueda y ordenación de datos. La elección entre usar una solución recursiva o iterativa depende en gran medida de la preferencia y experiencia del programador, la eficiencia y el tiempo de ejecución buscado, y sobre todo del tipo de problema que se va resolver.
DESVENTAJAS
Las funciones recursivas presentan algunas desventajas importantes frente a las técnicas iterativas, por lo que muchos programadores prefieren evitarlas, sin embargo, como se mencionó anteriormente, su uso depende del problema que se va a resolver. Entre sus desventajas comunes se encuentran:
- Mayor uso de pila de memoria: Cuando una función se llama a sí misma en repetidas ocasiones, se produce un mayor uso de memoria. Cada llamada crea una nueva instancia de la función y de sus variables locales en la pila de memoria, lo que puede significar un problema si se manejan grandes cantidades de datos.
- Dificultad de comprensión y de lectura: Las funciones recursivas requieren a menudo una comprensión profunda del problema y la lógica detrás del algoritmo, lo que puede dificultar su lectura y comprensión (especialmente para personas con pocos conocimientos en programación).
- Riesgo de caer en bucles infinitos: Si no se define correctamente el caso base se puede caer en bucles infinitos, lo que provocaría la saturación de la pila de memoria y consecuentemente el cuello de botella del programa.
- Rendimiento: En algunos casos, las funciones recursivas pueden ser menos eficientes que otras técnicas de programación, ya que pueden requerir más tiempo de ejecución y recursos de memoria.
DISEÑO DE UNA FUNCIÓN RECURSIVA
No todas las funciones se pueden llamar a sí mismas, para lograrlo, se tienen que diseñar específicamente para ello, cumpliendo las siguientes 3 condiciones:
1.- Caso base de parada: el caso base es cualquier expresión en la que se le dice a la función cuándo dejar de llamarse a sí misma. Si no se define un caso base, la recursión producirá un bucle infinito.
2.- Inducción: Paso recursivo que provoca una llamada recursiva, debe ser correcto para distintos parámetros de entrada.
3.- Convergencia: Cada paso recursivo debe acercar a un caso base. Se describe el problema en términos de problemas más sencillos.T
Todas las funciones recursivas pueden convertir con enfoques iterativos y viceversa.
FUNCIONAMIENTO
Cada vez que se llama a una función recursiva desde la función principal, se crea un juego de variables locales, de este modo, si la función hace una llamada a sí misma, se guardan sus variables y parámetros, usando la pila, y la nueva instancia de la función trabajará con su propia copia de las variables locales. Cuando esta segunda instancia de la función retorna, recupera las variables y los parámetros de la pila, y continua la ejecución en el punto en que había sido llamada. Cuando se alcanza el caso base, se comienza a desapilar la pila y se van retornando los valores que fueron guardados previamente en la pila para cada una de las llamadas recursivas, obteniendo así la solución.
A continuación, veremos un ejemplo de función recursiva, aplicada en un programa que calcula la suma de los elementos de un arreglo:
#include <iostream>
int sum_array(int arr[], int size) {
if (size == 0) { // Caso base: si el tamaño del arreglo es cero, devuelve cero
return 0;
} else {
return arr[size - 1] + sum_array(arr, size - 1); // Se llama a la función sum_array pasando el arreglo y su tamaño menos uno como argumentos, y se suma el último elemento del arreglo
}
}
int main() {
int size;
std::cout << "Ingrese el tamaño del arreglo: ";
std::cin >> size;
int arr[size];
for (int i = 0; i < size; i++) {
std::cout << "Ingrese un elemento: ";
std::cin >> arr[i];
}
int sum = sum_array(arr, size);
std::cout << "La suma de los elementos del arreglo es: " << sum << std::endl;
return 0;
}
El código ha sido probado en Code::Blocks en Windows, por lo que es completamente funcional.
Puedes descargar el código .CPP aquí.
NOTA: Si al correr el programa los acentos o caracteres especiales no se muestran correctamente, puedes usar esta solución: ¿Cómo mostrar acentos y caracteres especiales en programas escritos en C++?