¿Cuál es la mejor manera de depurar un algoritmo recursivo?

No lo hagas

La depuración debería ser un acto de último recurso. Debe tener una metodología de desarrollo de programas que reduzca la necesidad de depurar en primer lugar.

En particular, debe escribir ejemplos de su código antes de escribir su código. Luego escribe más ejemplos, también conocidos como pruebas. (Consulte Cómo diseñar programas, y en particular la respuesta de Shriram Krishnamurthi a ¿Cómo enseña el profesor Shriram Krishnamurthi el concepto de recursión?). Si su programa no funciona correctamente y todas sus pruebas pasan, significa que no ha realizado la prueba lo suficientemente bien.

Entonces, el siguiente paso es sondear el espacio de las entradas para encontrar una falla. Tenga en cuenta que para saber si algo falla, debe saber cuál es la salida esperada (porque una prueba relaciona entradas y salidas). Si no puede averiguar qué debe producir una entrada, tiene un problema mucho más fundamental: no sabe qué programa está tratando de escribir. Aléjese de la computadora y descubra eso primero.

Ahora, supongamos que ha llegado a este punto: tiene entradas con salidas esperadas de que el programa está fallando. Aquí hay algo realmente bueno: ¡La recursión funciona muy bien con las pruebas! Si tiene una función no recursiva, podría haber varias razones por las cuales la salida de la entrada dada no es correcta. Pero si es recursivo, (casi siempre) está creando un subproblema de la entrada errónea dada. Por lo tanto, no tiene que buscar helter-skelter para obtener una explicación del error. Descubre los subproblemas que está generando y cuáles son sus resultados esperados. Comprueba si están produciendo eso.

  • Si no, estás lidiando con un caso de falla demasiado grande cuando tienes uno más pequeño a mano, así que desciende recursivamente.
  • Si lo son, entonces ha aislado su problema. Tiene subproblemas que producen resultados correctos, pero la composición de las soluciones está fallando. Ahora deberías poder recorrer su composición para descubrir la falla.

Como beneficio adicional de seguir este protocolo de “depuración”, ahora ha agregado más pruebas a su código, y en particular ha agregado pruebas de regresión. Debido a que se sabe que los errores reaparecen (es decir, se sabe que el código regresa), detectará este o un error estrechamente relacionado temprano si ocurre nuevamente en el futuro.

NB: Supongo que estás programando de una manera principalmente funcional, porque eso es lo que todos deberían hacer de todos modos. (-:

No existe una diferencia real entre depurar un algoritmo recursivo y depurar cualquier otro algoritmo.

Por lo general, un algoritmo recursivo tiene tres partes:

  1. La parte que convierte el problema en un problema menor.
  2. La parte que trata con uno o más casos triviales del problema.
  3. La parte que trata con el estado de error.

Entonces, comenzaría pasando la entrada que se ocupa del n. ° 1 y n. ° 2: entrada que es pequeña, pero no del todo trivialmente pequeña. Asegúrese de que trata de convertir el problema en un problema más pequeño correctamente. Asegúrese de que trata con un caso trivial correctamente. Luego mire la sección de error y asegúrese de que la entrada incorrecta se trate correctamente.

(Hay advertencias: es posible que esté recordando sus resultados, lo que sería otra cosa que debe verificar. Es posible que esté llegando a un límite en la profundidad de la pila, lo cual es una realidad desafortunada cuando usa la recursión en muchos idiomas. Puede estar haciendo algo que no No funciona si estaba usando recursividad o no, como tratar de calcular 100 factorial y devolverlo como un entero de 32 bits).

Una excelente manera de investigar los problemas en los algoritmos recursivos es reducir el orden de la entrada hasta que el problema desaparezca.
Un algoritmo recursivo funciona resolviendo el problema P (n) resolviendo un conjunto de subproblemas similares P (n-1) que se resuelven resolviendo más (conjuntos) P (n-2) y así sucesivamente. Si se da cuenta de que la salida de P (n) es incorrecta, simplemente verifique los resultados en el conjunto P (n-1). Si son correctos, entonces debe observar de cerca la lógica que los une para resolver P (n). De lo contrario, mire más allá de los que están mal. Al mirar hacia abajo el tramo de “error” de la recursión, eventualmente encontrará el problema.

Una excelente manera de probar un algoritmo recursivo (o cualquier algoritmo) es implementar otra forma (digamos iterativa) del mismo algoritmo y lanzar una batería de casos de prueba a ambos y verificar que los resultados sean iguales. A menudo es fácil realizar cientos de miles (incluso millones) de pruebas en una implementación de esa manera. Calcular a mano incluso unos pocos cientos de casos de prueba de cualquier complejidad normalmente está completamente fuera de discusión.
A menudo hay una implementación ‘simple’ que es mucho más fácil ‘probar’ que es correcta y luego puede usarse para validar una forma más rápida pero más compleja.

También busque invariantes que puedan verificarse. La mejor manera de probar cualquier algoritmo de clasificación serio es arrojar un montón de casos de prueba. Algunos deben formarse a mano para garantizar la cobertura del código, pero la mayoría podrían ser casos aleatorios generados por máquina. Su script de prueba puede verificarlos todos verificando que el resultado esté realmente ordenado. No necesita “saber” la respuesta a muchos casos en absoluto …

Por lo general, no desea depurar un algoritmo recursivo que es difícil de seguir después de cierto tiempo. Pero en caso de que aún tenga que hacer lo mismo, sugeriría escribir los parámetros en cuestión y el número de iteración como un registro en un archivo.

Puede escribir un conjunto de aserciones que se adjuntan en varios puntos del programa. Cada vez que el programa se ejecuta más allá del punto de prueba, se verifica la aserción. Adjunte aserciones en el punto de inicialización para asegurarse de que el algoritmo se inicie con el valor corregido y adjunte una aserción en el punto de avance cuando el siguiente valor se deriva del anterior.

Si hay algún error en el programa se detectará muy pronto.

More Interesting

¿Cuáles son los 30 algoritmos más importantes que debe conocer para la programación competitiva?

¿Son las estructuras de datos y los requisitos previos de algoritmos para la arquitectura y organización de computadoras en un curso típico de CS? Estoy aprendiendo por mi cuenta, ¿cuál debería aprender primero? ¿Puedo aprenderlos en paralelo?

¿Qué es mejor: una lista enlazada de codificación o el uso de libs de plantillas estándar?

¿Necesito conocer algoritmos de aprendizaje automático para asegurar un trabajo como analista de datos?

Cómo obtener el valor más cercano al número al agregar elementos de matriz

¿Qué es la fuerza bruta?

¿Cómo funcionan los algoritmos de Google en los motores de búsqueda?

Cómo saber si un algoritmo es [matemática] O (n) [/ matemática], [matemática] O (2n) [/ matemática] o [matemática] O (n ^ 2) [/ matemática]

¿Qué tipo de algoritmo SLAM utiliza Teslas? ¿O incluso están usando algoritmos SLAM?

¿Para qué sirve un tamaño de obtención de matriz?

Entiendo los conceptos básicos de Java y puedo codificarlo fácilmente, pero no puedo codificar casos complejos. ¿Qué puedo hacer para mejorar mis habilidades de codificación?

Cómo imprimir rutas en forma DFS en gráficos

¿Cuáles son algunos de los algoritmos comunes y estrategias de diseño utilizados por los desarrolladores de juegos sin fin?

Si recientemente completé un campo de entrenamiento y todo lo que queda para conseguir un trabajo es la prueba técnica, ¿cuántas horas serán suficientes los algoritmos de aprendizaje?

¿Cómo realizan las computadoras la multiplicación y la complejidad del tiempo?