Cómo comprender y utilizar la recursividad correctamente

Cómo comprender y utilizar la recursividad correctamente

¿Qué es la recursividad?

  1. La recursividad es un algoritmo (o técnica de programación) muy utilizado. La recursividad se utiliza en la codificación de muchas estructuras de datos y algoritmos, como la búsqueda en profundidad DFS, el recorrido de árbol binario frontal-intermedio-posterior al orden, y así sucesivamente.
  2. La forma en que un método o función se llama a sí mismo se llama llamada recursiva, el proceso de llamada se llama "paso" y el proceso de retorno se llama "recursivo".

¿Por qué utilizar la recursividad? ¿Ventajas y desventajas de la recursividad?

  • Ventajas: el código es conciso y fácil de entender. (Por ejemplo, en el recorrido pre / medio / post-orden del árbol, la implementación de la recursividad es obviamente más simple que el bucle).
  • Desventajas: el consumo de tiempo y espacio es grande, hay doble cálculo y existe el riesgo de desbordamiento de la pila.

Tres condiciones que deben cumplirse para la recursividad

Un problema se puede resolver mediante recursividad siempre que se cumplan las tres condiciones siguientes al mismo tiempo:

  1. La solución de un problema se puede descomponer en soluciones de varios subproblemas.
  2. Este problema es el mismo que el subproblema después de la descomposición, excepto que la escala de datos es diferente, la idea de la solución es exactamente la misma
  3. Existe una condición de terminación recurrente

¿Cómo escribir código recursivo?

La clave para escribir código recursivo es encontrar la ley de cómo dividir los problemas grandes en problemas pequeños y, en base a esto, escribir una fórmula recursiva, luego considerar la condición de terminación y finalmente traducir la fórmula de recursión y la condición de terminación en código.

  1. Primero ponga la condición de terminación recursiva y la fórmula recursiva juntas
f(1) = 1;
f(2) = 2;
f(n) = f(n-1)+f(n-2)
  1. Y luego en código recursivo
int f(int n) {
    
    
  if (n == 1) return 1;
  if (n == 2) return 2;
  return f(n-1) + f(n-2);
}

Cómo entender el código recursivo

Para el código recursivo, si intenta averiguar todo el proceso recursivo y recursivo, en realidad entrará en un malentendido de pensamiento . En muchos casos, nos resulta difícil de entender, la razón principal es que nos hemos creado este tipo de barrera de comprensión. ¿Cuál es la forma correcta de pensar?

Si un problema A se puede descomponer en varios subproblemas B, C y D, puede asumir que los subproblemas B, C y D se han resuelto y luego pensar en cómo resolver el problema A sobre esta base. . Además, solo necesita pensar en la relación entre la pregunta A y los subproblemas B, C y D. No necesita pensar en subproblemas y subproblemas, subproblemas y subproblemas. subproblemas Relación entre. Enmascare los detalles recursivos, para que sea mucho más fácil de entender.

Por lo tanto, siempre que nos encontremos con la recursividad, la abstraemos en una fórmula recursiva , en lugar de pensar en capas de relaciones de llamadas, y no intentamos usar el cerebro humano para descomponer cada paso de la recursividad.

Preguntas frecuentes sobre la recursividad

Desbordamiento de pila

La llamada a la función usa la pila para almacenar variables temporales. Cada vez que se llama a una función, la variable temporal se encapsulará como un marco de pila y se insertará en la pila de memoria, y la pila se abrirá cuando la función regrese. El espacio de la pila del sistema o de la pila de la máquina virtual generalmente no es grande. Si los datos que se van a resolver de forma recursiva son grandes, el nivel de llamada es profundo y siempre se inserta en la pila, habrá riesgo de desbordamiento de la pila.

Solución:
puede limitar la profundidad máxima de llamadas recursivas en el código y devolver directamente un error si excede. Los ejemplos de pseudocódigo son los siguientes:

// 该例子只适用于一个f分解为一个f
// 全局变量,表示递归的深度。
int depth = 0;

int f(int n) {
    
    
  ++depth;
  if (depth > 1000) throw exception;
  
  if (n == 1) return 1;
  return f(n-1) + 1;
}

Pero este enfoque no resuelve completamente el problema, porque la profundidad de recursión máxima permitida está relacionada con el espacio de pila restante del subproceso actual y no se puede calcular de antemano. Si se calcula en tiempo real, el código es demasiado complejo, lo que afectará la legibilidad del código.

Cálculo repetido

Para evitar cálculos repetidos, podemos guardar la f (k) resuelta a través de una estructura de datos (como una tabla hash). Cuando la llamada recursiva llega a f (k), primero vea si ya se ha resuelto. Si es así, recuperará directamente el valor de la tabla hash y lo devolverá sin repetir los cálculos.

resumen

  • La recursividad es una técnica de codificación muy eficiente y concisa. Siempre que se cumplan las "tres condiciones", el problema se puede resolver mediante código recursivo.
  • Sin embargo, el código recursivo también es difícil de escribir y comprender. La clave para escribir código recursivo es no eludirse, la postura correcta es escribir la fórmula recursiva, encontrar la condición de terminación y luego traducirla a código recursivo.
  • Aunque el código recursivo es conciso y eficiente, el código recursivo también tiene muchos inconvenientes. Por ejemplo, el desbordamiento de la pila, los cálculos repetidos, las llamadas a funciones consumen mucho tiempo y la complejidad del espacio es alta. Por lo tanto, al escribir código recursivo, estos efectos secundarios deben controlarse.

¿Cómo depurar código recursivo?

  1. Imprima el registro que encontró que el valor recursivo.
  2. Combine puntos de interrupción condicionales para la depuración.

Depurar la recursividad es como escribir una recursividad. No te dejes atrapar por los detalles de cada paso. La clave es confirmar si la relación de recursividad y la condición final son correctas. Usa puntos de interrupción condicionales para centrarte en depurar los dos primeros pasos y los dos últimos pasos.

Toma nota de: 15/03/2020

Supongo que te gusta

Origin blog.csdn.net/curtis0730/article/details/104879484
Recomendado
Clasificación