Para explicar la recursividad , utilizo una combinación de explicaciones diferentes, generalmente para tratar de:
- explicar el concepto
- explica por qué es importante
- explica cómo conseguirlo.
Para empezar, Wolfram | Alpha lo define en términos más simples que Wikipedia :
Una expresión tal que cada término se genera repitiendo una operación matemática particular.
Matemáticas
Si su estudiante (o la persona que usted explica también, a partir de ahora diré que estudiante) tiene al menos algunos antecedentes matemáticos, obviamente ya han encontrado recursividad al estudiar series y su noción de recursividad y su relación de recurrencia .
Una muy buena manera de comenzar es demostrar con una serie y decir que se trata simplemente de la recursividad:
- una función matemática ...
- ... que se llama a sí mismo para calcular un valor correspondiente a un enésimo elemento ...
- ... y que define algunos límites.
Por lo general, obtienes un "huh huh, whatev 'en el mejor de los casos porque todavía no lo usan, o más probablemente solo un ronquido muy profundo.
Ejemplos de codificación
Por lo demás, en realidad es una versión detallada de lo que presenté en el Addendum de mi respuesta a la pregunta que usted señaló con respecto a los punteros (mal juego de palabras).
En esta etapa, mis alumnos generalmente saben cómo imprimir algo en la pantalla. Suponiendo que estamos usando C, ellos saben cómo imprimir un solo carácter usando write
o printf
. También saben acerca de los lazos de control.
Normalmente recurro a algunos problemas de programación repetitivos y simples hasta que lo consiguen:
- la operación factorial ,
- una impresora de alfabeto,
- una impresora de alfabeto invertida,
- La operación de exponenciación .
Factorial
Factorial es un concepto matemático muy simple de entender, y la implementación está muy cerca de su representación matemática. Sin embargo, es posible que no lo entiendan al principio.
Alfabetos
La versión del alfabeto es interesante para enseñarles a pensar sobre el orden de sus declaraciones recursivas. Al igual que con los punteros, simplemente te lanzarán líneas al azar. El punto es llevarlos a la conclusión de que un bucle puede invertirse modificando las condiciones O simplemente invirtiendo el orden de las declaraciones en su función. Ahí es donde ayuda la impresión del alfabeto, ya que es algo visual para ellos. Simplemente pídales que escriban una función que imprima un carácter para cada llamada, y se llame a sí mismo de forma recursiva para escribir el siguiente (o anterior).
Ventiladores de FP, omita el hecho de que imprimir cosas en el flujo de salida es un efecto secundario por ahora ... No seamos demasiado molestos en el frente de FP. (Pero si usa un lenguaje con soporte de lista, siéntase libre de concatenarse con una lista en cada iteración y simplemente imprima el resultado final. Pero generalmente comienzo con C, que desafortunadamente no es el mejor para este tipo de problemas y conceptos) .
Exponenciación
El problema de exponenciación es un poco más difícil ( en esta etapa de aprendizaje). Obviamente, el concepto es exactamente el mismo que para un factorial y no hay complejidad adicional ... excepto que tiene múltiples parámetros. Y eso suele ser suficiente para confundir a las personas y desecharlas al principio.
Su forma simple:
puede expresarse así por recurrencia:
Más fuerte
Una vez que estos problemas simples han sido mostrados Y re-implementados en tutoriales, puede dar ejercicios un poco más difíciles (pero muy clásicos):
- Los números de Fibonacci ,
- El mayor divisor común ,
- El problema de las 8 reinas ,
- El juego Towers of Hanoi ,
- Y si tiene un entorno gráfico (o puede proporcionar códigos auxiliares para él o para una salida de terminal o ya pueden administrarlo), cosas como:
- Y para ejemplos prácticos, considere escribir:
- un algoritmo transversal del árbol,
- un simple analizador de expresiones matemáticas,
- Un juego de buscaminas.
Nota: Una vez más, algunos de estos realmente no son más difíciles ... Simplemente abordan el problema desde exactamente el mismo ángulo, o uno ligeramente diferente. Pero la práctica hace la perfección.
Ayudantes
Una referencia
Algunas lecturas nunca están de más. Bueno, al principio, y se sentirán aún más perdidos. Es el tipo de cosa que crece en ti y que se sienta en la parte posterior de tu cabeza hasta que un día te das cuenta de que finalmente lo entiendes. Y luego piensas en estas cosas que leíste. La recursión , la recursividad en Ciencias de la Computación y las páginas de relación de recurrencia en Wikipedia funcionarían por ahora.
Nivel / Profundidad
Asumiendo que sus estudiantes no tienen mucha experiencia en codificación, proporcione talones de código. Después de los primeros intentos, deles una función de impresión que pueda mostrar el nivel de recurrencia. Imprimir el valor numérico del nivel ayuda.
El diagrama de apilar como cajones
La sangría de un resultado impreso (o la salida del nivel) también ayuda, ya que proporciona otra representación visual de lo que está haciendo su programa, abriendo y cerrando contextos de pila como cajones o carpetas en un explorador del sistema de archivos.
Acrónimos recursivos
Si su estudiante ya está un poco versado en la cultura informática, es posible que ya use algunos proyectos / softwares con nombres que usan acrónimos recursivos . Ha sido una tradición que existe desde hace algún tiempo, especialmente en proyectos GNU. Algunos ejemplos incluyen:
Recursivo:
- GNU - "GNU no es Unix"
- Nagios - "Nagios no va a insistir en la santidad"
- PHP - "Preprocesador de hipertexto PHP" (y originalmente toda la "Página de inicio personal")
- Vino - "El vino no es un emulador"
- Zile - "Zile es Emacs con pérdida"
Mutuamente recursivo:
- HURD - "HIRD of Unix-Replacing Daemons" (donde HIRD es "HURD of Interface que representa la profundidad")
Haga que traten de inventar los suyos.
Del mismo modo, hay muchos casos de humor recursivo, como la corrección de búsqueda recursiva de Google . Para obtener más información sobre la recursividad, lea esta respuesta .
Errores y aprendizaje adicional
Algunos problemas con los que la gente suele luchar y para los que necesita saber respuestas.
¿Por qué, oh Dios, por qué?
¿Por qué harías eso? Una razón buena pero no obvia es que a menudo es más simple expresar un problema de esa manera. Una razón no tan buena pero obvia es que a menudo se necesita menos tipeo (sin embargo, no los haga sentir demasiado solo por usar la recursividad ...).
Algunos problemas son definitivamente más fáciles de resolver cuando se utiliza un enfoque recursivo. Por lo general, cualquier problema que pueda resolver utilizando un paradigma Divide and Conquer se ajustará a un algoritmo de recursión de múltiples ramificaciones.
¿Qué es N otra vez?
¿Por qué mi n
o (sea cual sea el nombre de su variable) es diferente cada vez? Los principiantes generalmente tienen problemas para comprender qué son una variable y un parámetro, y cómo las cosas nombradas n
en su programa pueden tener valores diferentes. Entonces, si este valor está en el ciclo de control o en la recursividad, ¡eso es aún peor! Sea amable y no use los mismos nombres de variables en todas partes, y deje en claro que los parámetros son solo variables .
Condiciones finales
¿Cómo determino mi condición final? Eso es fácil, solo haz que digan los pasos en voz alta. Por ejemplo, para el inicio factorial desde 5, luego 4, luego ... hasta 0.
El diablo está en los detalles
No hable con cosas tempranas sobre optimización de llamadas de cola . Lo sé, lo sé, el coste total de propiedad es bueno, pero al principio no les importa. Déles algo de tiempo para comprender el proceso de una manera que funcione para ellos. Siéntete libre de destruir su mundo nuevamente más tarde, pero dales un descanso.
Del mismo modo, no hable directamente desde la primera conferencia sobre la pila de llamadas y su consumo de memoria y ... bueno ... el desbordamiento de la pila . A menudo doy clases particulares a estudiantes en privado que me muestran conferencias donde tienen 50 diapositivas sobre todo lo que hay que saber sobre la recursividad cuando apenas pueden escribir un bucle correctamente en esta etapa. Ese es un buen ejemplo de cómo una referencia ayudará más adelante, pero en este momento solo te confunde profundamente.
Pero por favor, a su debido tiempo, deje en claro que hay razones para seguir la ruta iterativa o recursiva .
Recursividad mutua
Hemos visto que las funciones pueden ser recursivas e incluso que pueden tener múltiples puntos de llamada (8 reinas, Hanoi, Fibonacci o incluso un algoritmo de exploración para un buscaminas). Pero, ¿qué pasa con las llamadas recursivas recíprocas ? Comience con las matemáticas aquí también. f(x) = g(x) + h(x)
donde g(x) = f(x) + l(x)
y h
y l
solo hacer cosas.
Comenzar solo con series matemáticas hace que sea más fácil escribir e implementar, ya que el contrato está claramente definido por las expresiones. Por ejemplo, las secuencias femeninas y masculinas de Hofstadter :
Sin embargo, en términos de código, es de notar que la implementación de una solución mutuamente recursivo a menudo conduce a la duplicación de código y más bien debería simplificarse en una sola forma recursiva (Ver Peter Norvig 's Solución Cada Sudoku .