Está en la página 1de 6
176 Estructura de datos en C++ La implementacién del algoritmo iterativo equivalente ser: El ticmpo de ejecucién del algoritmo crece linealmente con » ya que el bucle es el término dominante. Se puede afirmar que t (n} €5 O(n) La versién recursiva: ynacei tn - 1) + Fibenaced in 2) En cuanto al tiempo de ejecucién del algoritmo recursivo ya no es tan elemental establecer uuna cota superior. Observe que, por ejemplo, para calcular fibenaces (6) se calcula, recursi- vamente, fibonace: (5) y cuando termine este £:bonacci (4). A su vez, el céleulo de £i- bonaces (5) supone caleular £ihonacei (4) y £ibenaces (3): se esté repitiendo el célculo de fibonacei (4), es una pérdida de tiempo. Por inducci6n matemtica se puede demostrar que el miimero de lamadas recursivas erece exponencialmente, t(n) es O(6") con ¢ = LYS, A tener en cuenta La formulacién recursiva de una funcién matematica puede ser m uy ineficiente sobre todo si se repiten calculos realizados anteriormente. En estos caso el algoritmo iterati- vo, aunque no sea tan evidente, es notablemente mas eficiente. 7.2. FUNCIONES RECURSIVAS Una funcién recursiva cs una funcién que se invoca a si mismo de forma directa o indirecta, En recursién directa el cédigo de Ia funcién ©() contiene una sentencia que invoca a f(), mientras que en recursi6n indirecta la funcién £ () invoca a una funci6n ¢ {) que invoca a su. vex a la funcién p (), y as{ sucesivamente hasta que se invoca de nuevo a la funcién £ () www.FreeLibros.me Algoritmos Recursivos 177 Un requisito para que un algoritmo recursivo sea correcto es que no genere una secuencia infinita de llamadas sobre s{ mismo, Cualquier algoritmo que genere una secuencia de este tipo no puede terminar nunca. En consecuencia, la definicién recursiva debe incluir una condicién de salida, se denomina componente base, en ta cual fin) se defina directamente (es decir, no recursivamente) para uno 0 mas valores de 7. En definitiva, debe existir una “forma de salir” de la secuencia de lamadas recursivas. Asf, cen el algoritmo que calcula la suma de los n primeros enteros: pt sin- ap noa la condicién de salida o componente base es $ (n) = I para n = 1, En el ejemplo del algoritmo recursivo de la serie de Fibonacci: F, = OYE, = Lconstituyen el componente base o condiciones de salida y=, = Foy + Ey2 5 el componente recursivo, Una funcién recursiva correcta debe incluir un componente base ‘0 condicién de salida ya que en caso contrario se produce una recursién infinita Una funcién es recursiva si se llama a si mismo, directamente o bien indirectamente a través de otra funcién ¢ () . Es necesario contemplar un caso base que deter mina la salida de las llamadas recursivas. PROBLEMA 7.1. Escribir una funcién recursiva que calcule el factorial de un nimero ny un programa que pida un numero entero y escr iba su factorial llamando a la funcién, La componente base de la funcién recursiva que calcula el factorial es que n = 0, 0 inclu: son = La que en ambos caso el factorial es 1, El problema se resuelve recordando la defi- nicién de factorial Hinelude using namespace std; void funciona (char oh; void funcians (char ci? nt main() void funcionaichar ef void funcions (char ef fone www.FreeLibros.me Algoritmos Recursivos 179 7.2.2. Condicién de terminacién de la recursion ‘Cuando se implementa una funcién recursiva sera preciso considerar una condicién de termi- naci6n, ya que en caso contrario la funciGn continuaria indefinidamente llamndose a sf misma y llegaria un momento en que la pila que registra las llamadas se desbordaria. En consecuencia, se necesita establecer en toda funcién recursiva la condicién de parada de las Hamada recur- sivas. Por ejemplo, la condicién de parada de la funcién factoria: () (Problema. 7.1) ‘ocurre cuando n es 1 0 9, en ambos casos el factorial es 1. Es importante que cada llamada suponga un acercamiento a la condicién de parada, en factorial () cada llamada dectemen- tael valor de n y, por consiguiente, se acerca a la condicién n == 1 En el Problema 7.2 se produce recursién mutua entre funcionA{) y funcionB(), la condici6n de parada es © == 'A', La primera llamada se hace cone = "2", cada llamada mmutua decrementa c y, por tanto, se va acercando a la letra En un algoritmo recursivo, se entiende por caso base el que se resueive sin recursion, directamente, con unas pocas sentencias elementales. El caso base se ejecuta cuan- do se alcanzala_condicién de par ada de llamadas recursiv as. Para que funcione la recursién el progreso de las llamadas debe tender a la condicién de par ada, 7.3. RECURSION VERSUS ITERACION En las secciones anteriores se han estudiado varios algoritmos que se pueden implementar fa cilmente de modo recursive, 0 bien de modo iterativo. En esta seccién se comparan los dos ‘enfoques y se examinan las razones por las que el programador puede elegir un enfoque u otro segin la situaciGn especitica. Tanto la iteracién como la recursién se basan en una estructura de control: la iteracién iliza una estructura repetitiva y la recursién utiliza una estructura de seleccién. La iteraci6n ¥ la recursi6n implican ambas repeticiGn: la iteracién utiliza explicitamente una estructura re petitiva mientras que la recursién consigue la repeticién mediante sucesivas Hamadas a la fun- cién, La iteracién y recursién implican cada una un test de terminaci6n (condicién de parada), La iteracién termina cuando la condicién del bucle no se cumple, mientras que la recursién termina cuando se reconoce un caso base (se aleanza la condicién de parada). La recursién tiene muchas desventajas. Se invoca repetidamente al mecanismo de Ila- mada a funcidn y, en consecuencia, se necesita un tiempo suplementario para realizar cada Hamada. Esta caracteristica puede resultar cara en tiempo de procesador y espacio de me- moria. Cada llamada recursiva produce que se realice una nueva creacién y copia de las variables de la funcién; esto puede consumir mucha memoria e incrementar el tiempo de ejecucién, Por el contrario, la iteracién se produce dentro de una funcién de modo que las ‘operaciones suplementarias en la llamada a la funcién y asignacién de memoria adicional son omitidas, Entonces, jeusles son las razones para elegir la recursién? La razén fundamental es que existen numerosos problemas complejos que poseen naturaleza recursiva y, en consecuencia, son més féciles de implementar con algoritmos de este tipo. Sin embargo, en condiciones eri- ticas de tiempo y de memoria, es decir, cuando el consumo de tiempo y memoria sean decisivos ‘© concluyentes para la resolucién del problema, la solucién a elegir debe ser, normalmente, la iterativa, www.FreeLibros.me 180 Estructura de datos en C++ Nota de ejecucién Cuaiquier problema que se puede resoher recursivamente, tiene al menos una solucién iterativa utilizando una pila. Se elige el ent oque recursive frente al enf oque iterative ‘cuando el recursivo es mas natural para la resolucién del problema y produce un pro- {grama mas facil de comprender y depurar. Otra raz6n para elegir una solucion recursi- vva es que una solucién iterativa puede no ser clara ni evidente. Consejo de programacién ‘Se ha de e vitar utlizar recursividad en situaciones de rendimiento critica 0 xigencia de altas prestaciones en tiempo y memor ia, ya que las llamadas recursiv as emplean tiempo y consumen memor ia adicional. No es con veniente el uso de una llamada re- cursiva para sustituir un simple bucle. EJEMPLO 7.3. Dado un niimero natur al n obtener la suma de los digitos de que consta, Presentar un algoritmo recursivo y otro iterativo, El ejemplo offece una estructura clara de comparacién entre la resolucién de modo iterati- vo y de modo recursivo. Se asume que el niimero m es natural y que, por tanto, no tiene signo, la suma de los digitos se puede expresar: sura = suma(n / 26) + modulo (ny 19) par: Por ejemplo, sin = Suma ~ suma(259 J 16) + modulo (259/10) > 2454 9> 16 J ma = suma(25 / 10) + sag 1 aura = sume (2 / 20) ea aot Se puede observar que el caso base, el que se resuelve directamente, es n < 9 y asu vez es la condicisn de parada, Solucién recursiva www.FreeLibros.me Algoritmos Recursives 181 Solucién iterativa La solucién iterativa de hallar la suma de los digitos del ndmero n se construye con un bucle ‘mientras, repitiendo la acumulacién del resto de dividir n por 10 y actualizar n en el cociente. La condicién de salida del bucle es que sea menor o igual que 9 while (n> 9 a /= 103 return (sua +n); 7.3.1. Directrices en la toma de decision iteracién/recursion 1. Considérese una solucién recursiva s6lo cuando una solucin iterativa sencilla no sea posible. 2. Utilicese una soluci6n recursiva sélo cuando la ejecucién y eficiencia de la memoria de Ja solucién esté dentro de limites aceptables considerando las limitaciones del sistema, 3. Si son posibles las dos soluciones, iterativa y recursiva, la solucién recursiva siempre requerira més tiempo y espacio debido a las lamadas adicionales a las funcidnes. ciertos problemas, la recursién conduce naturalmente a soluciones que son mucho ms fiables de leer y comprender que su correspondiente iterativa, En estos casos los beneficios obtenidos con la claridad de la solucién suelen compensar el coste extra (en tiempo y memoria) de la ejecucién de un programa recursivo, Consejo de programacién Una funcién recursiva que tiene la llamada recursiva como titima sentencia (recursién final) puede transformarse facilmente en iter ativa reemplazando la llamada mediante tun bucle condicional que chequea el caso base. 7.3.2. Recursién infinita La iteraci6n y la recursi6n pueden producirse infinitamente. Un bucle infinito ocurre sila prue~ ba o test de continuacién de bucle nunca se vuelve falsa; una recursién infinita ocurre si la capa de recursién no reduce el problema en cada ocasién de modo que converja sobre el caso base 0 condiciGn de salida, En realidad la recursién infinita significa que cada llamada recursiva produce otra Ilama- da recursiva y ésta a su vez otra llamada recursiva y asi para siempre. En la préctica dicha funcién se ejecutard hasta que la computadora agota la memoria disponible y se produce una. terminacién anormal del programa, www.FreeLibros.me

También podría gustarte