Como explica el título, tengo una pregunta de programación muy fundamental que todavía no he podido asimilar. Filtrar todos los (extremadamente inteligentes) "Para comprender la recursividad, primero debe comprender la recursividad". respuestas de varios hilos en línea todavía no lo entiendo.
Entendiendo que cuando nos enfrentamos a no saber lo que no sabemos, podemos tender a hacer las preguntas equivocadas o hacer las preguntas correctas de manera incorrecta. Compartiré lo que "creo". Mi pregunta es con la esperanza de que alguien con una perspectiva similar pueda compartir algo. ¡Un poco de conocimiento que me ayudará a encender la bombilla recursiva!
Aquí está la función (la sintaxis está escrita en Swift):
func sumInts(a: Int, b: Int) -> Int {
if (a > b) {
return 0
} else {
return a + sumInts(a: a + 1, b: b)
}
}
Usaremos 2 y 5 como nuestros argumentos:
println(sumInts(a: 2, b: 5))
Obviamente la respuesta es 14. Pero no tengo claro cómo se logra ese valor.
Estos son mis 2 problemas:
La función se llama de forma recursiva hasta que se cumple una condición. Esa condición es a> b. Cuando se cumple esta condición, devuelve 0. A primera vista, esperaría que el valor devuelto fuera 0, lo que obviamente es incorrecto.
Imprimir el valor de 'a' en cada iteración produce un valor que esperaría: 2, 3, 4, 5 (en cuyo punto 5 + 1> b que cumple la primera condición: a> b) pero todavía no ' Veamos cómo se logra el valor de 14.
Mi primer pensamiento es que algo similar a lo siguiente está sucediendo mágicamente:
var answer = a;
answer += a+1 until a > b;
return answer;
Así que descartando la magia, simplemente no obtengo nada. Me encantaría entender lo que está sucediendo más que implícitamente.
Si alguien pudiera explicar amablemente qué sucede técnicamente durante este tipo de función y por qué el resultado no es 0 y cómo, eventualmente, a + sumInts(a: a + 1, b: b) = 14
estaría para siempre en deuda con usted.
fuente
LearnYouARecursion
, conjuntos de problemas completos de un profesor de clase mundial!Respuestas:
Creo que la confusión proviene de pensar en ella como "la misma función" que se llama muchas veces. Si lo considera como "muchas copias de la misma función que se llaman", entonces puede ser más claro:
Solo una copia de la función devuelve 0, y no es la primera (es la última). Entonces, el resultado de llamar al primero no es 0.
Para la segunda confusión, creo que será más fácil deletrear la recursividad en inglés. Lea esta línea:
como "devuelve el valor de 'a' más (el valor de retorno de otra copia de la función, que es el valor de la copia de 'a' más (el valor de retorno de otra copia de la función, que es el valor de la segunda copia de ' a 'más (... ", con cada copia de la función generando una nueva copia de sí misma con un aumento de 1, hasta que se cumpla la condición a> b.
En el momento en que alcanza la condición a> b siendo verdadera, tiene una pila larga (potencialmente arbitraria) de copias de la función en medio de la ejecución, todas esperando el resultado de la siguiente copia para averiguar qué debe agregar a 'a'.
(editar: también, algo a tener en cuenta es que la pila de copias de la función que menciono es algo real que ocupa memoria real, y bloqueará su programa si se vuelve demasiado grande. El compilador puede optimizarlo en algunos casos, pero agotar el espacio de la pila es una limitación significativa y desafortunada de las funciones recursivas en muchos idiomas)
fuente
a
yb
.sumInts(2,5)
Esto es lo que pensaría la informática si pudiera:Como puede ver, algunas llamadas a la función en
sumInts
realidad devuelven 0, sin embargo, este no es el valor final porque la computadora aún tiene que agregar 5 a ese 0, luego 4 al resultado, luego 3, luego 2, como se describe en las últimas cuatro oraciones de los pensamientos de nuestra computadora. Tenga en cuenta que en la recursividad, la computadora no solo tiene que calcular la llamada recursiva, también tiene que recordar qué hacer con el valor devuelto por la llamada recursiva. Hay un área especial de la memoria de la computadora llamada pila donde se guarda este tipo de información, este espacio es limitado y las funciones que son demasiado recursivas pueden agotar la pila: este es el desbordamiento de pila que da su nombre a nuestro sitio web más querido.Su declaración parece hacer la suposición implícita de que la computadora olvida dónde estaba al hacer una llamada recursiva, pero no es así, por eso su conclusión no coincide con su observación.
Esto se debe a que el valor de retorno no es en
a
sí mismo, sino la suma del valor dea
y el valor devuelto por la llamada recursiva.fuente
sumInts
para que realmente escriba los "pensamientos de la computadora". Una vez que haya escrito una parte de tales funciones, ¡probablemente lo habrá "entendido"!Para comprender la recursividad, debe pensar en el problema de una manera diferente. En lugar de una gran secuencia lógica de pasos que tiene sentido en su conjunto, usted toma un problema grande y lo divide en problemas más pequeños y los resuelve, una vez que tenga una respuesta para los subproblemas, combine los resultados de los subproblemas para hacer el solución al problema más grande. Piense en usted y sus amigos que necesitan contar la cantidad de canicas en un cubo enorme. Cada uno toma un cubo más pequeño y va a contarlos individualmente y cuando haya terminado, sume los totales. Bueno, ahora si cada uno de ustedes encuentra un amigo y divide los cubos más, entonces solo tiene que esperar a que estos otros amigos calcule sus totales, devuélvaselo a cada uno de ustedes, sume. Y así.
Debe recordar que cada vez que la función se llama a sí misma de forma recursiva, crea un nuevo contexto con un subconjunto del problema, una vez que se resuelve esa parte, se devuelve para que se pueda completar la iteración anterior.
Déjame mostrarte los pasos:
Una vez que sumInts (a: 6, b: 5) se ha ejecutado, los resultados se pueden calcular, por lo que, al volver a subir la cadena con los resultados, obtendrá:
Otra forma de representar la estructura de la recursividad:
fuente
La recursividad es un tema complicado de entender y no creo que pueda hacerle justicia aquí. En su lugar, intentaré centrarme en la pieza de código particular que tienes aquí y trataré de describir tanto la intuición de por qué funciona la solución como la mecánica de cómo el código calcula su resultado.
El código que ha proporcionado aquí resuelve el siguiente problema: desea saber la suma de todos los números enteros desde a hasta b, inclusive. Para su ejemplo, desea la suma de los números del 2 al 5, inclusive, que es
Al intentar resolver un problema de forma recursiva, uno de los primeros pasos debería ser descubrir cómo dividir el problema en un problema más pequeño con la misma estructura. Así que suponga que desea sumar los números del 2 al 5, inclusive. Una forma de simplificar esto es notar que la suma anterior se puede reescribir como
Aquí, (3 + 4 + 5) resulta ser la suma de todos los números enteros entre 3 y 5, inclusive. En otras palabras, si quieres saber la suma de todos los números enteros entre 2 y 5, comienza calculando la suma de todos los números enteros entre 3 y 5, luego suma 2.
Entonces, ¿cómo se calcula la suma de todos los números enteros entre 3 y 5, inclusive? Bueno, esa suma es
que se puede pensar en cambio como
Aquí, (4 + 5) es la suma de todos los números enteros entre 4 y 5, inclusive. Entonces, si quisieras calcular la suma de todos los números entre 3 y 5, inclusive, calcularías la suma de todos los números enteros entre 4 y 5, luego sumarías 3.
¡Aquí hay un patrón! Si desea calcular la suma de los números enteros entre ayb, inclusive, puede hacer lo siguiente. Primero, calcule la suma de los números enteros entre a + 1 y b, inclusive. Luego, agregue a ese total. Notará que "calcular la suma de los números enteros entre a + 1 y b, inclusive" resulta ser más o menos el mismo tipo de problema que ya estamos tratando de resolver, pero con parámetros ligeramente diferentes. En lugar de calcular desde a hasta b, inclusive, estamos calculando desde a + 1 hasta b, inclusive. Ese es el paso recursivo: para resolver el problema más grande ("suma de a a b, inclusive"), reducimos el problema a una versión más pequeña de sí mismo ("suma de a + 1 a b, inclusive").
Si echas un vistazo al código que tienes arriba, notarás que hay este paso en él:
Este código es simplemente una traducción de la lógica anterior: si desea sumar de a a b, inclusive, comience sumando a + 1 a b, inclusive (esa es la llamada recursiva as
sumInt
), luego agreguea
.Por supuesto, este enfoque por sí solo no funcionará. Por ejemplo, ¿cómo calcularía la suma de todos los números enteros entre 5 y 5 inclusive? Bien, usando nuestra lógica actual, calcularías la suma de todos los enteros entre 6 y 5, inclusive, luego sumarías 5. Entonces, ¿cómo calculas la suma de todos los enteros entre 6 y 5, inclusive? Bueno, usando nuestra lógica actual, calcularías la suma de todos los enteros entre 7 y 5, inclusive, luego sumarías 6. Notarás un problema aquí - ¡esto sigue y sigue!
En la resolución recursiva de problemas, es necesario que haya alguna forma de dejar de simplificar el problema y, en su lugar, ir a resolverlo directamente. Por lo general, encontrará un caso simple en el que la respuesta se puede determinar de inmediato, luego estructurará su solución para resolver casos simples directamente cuando surjan. Esto se denomina típicamente un caso base o una base recursiva .
Entonces, ¿cuál es el caso base en este problema en particular? Cuando sumas números enteros de aab, inclusive, si a es mayor que b, entonces la respuesta es 0, ¡no hay números en el rango! Por lo tanto, estructuraremos nuestra solución de la siguiente manera:
Ahora, compare este pseudocódigo con su código real:
Tenga en cuenta que existe casi exactamente un mapa uno a uno entre la solución descrita en pseudocódigo y este código real. El primer paso es el caso base: en el caso de que pida la suma de un rango vacío de números, obtendrá 0. De lo contrario, calcule la suma entre a + 1 yb, luego agregue a.
Hasta ahora, he dado solo una idea de alto nivel detrás del código. Pero tenías otras dos muy buenas preguntas. Primero, ¿por qué esto no siempre devuelve 0, dado que la función dice que devuelva 0 si a> b? En segundo lugar, ¿de dónde vienen realmente los 14? Veamos estos a su vez.
Probemos con un caso muy, muy simple. ¿Qué pasa si llamas
sumInts(6, 5)
? En este caso, rastreando el código, verá que la función simplemente devuelve 0. Eso es lo correcto, no hay números en el rango. Ahora, intente algo más difícil. ¿Qué pasa cuando llamassumInts(5, 5)
? Bueno, esto es lo que sucede:sumInts(5, 5)
. Caemos en elelse
Caemos rama, que devuelve el valor de `a + sumInts (6, 5).sumInts(5, 5)
poder determinar quésumInts(6, 5)
es, necesitamos pausar lo que estamos haciendo y hacer una llamadasumInts(6, 5)
.sumInts(6, 5)
se llama. Entra en laif
sucursal y regresa0
. Sin embargo, esta instancia desumInts
fue llamada porsumInts(5, 5)
, por lo que el valor de retorno se comunicasumInts(5, 5)
a la persona que llama de nivel superior, no a ella.sumInts(5, 5)
ahora puede calcular5 + sumInts(6, 5)
para volver5
. Luego lo devuelve a la persona que llama de nivel superior.Observe cómo se formó el valor 5 aquí. Comenzamos con una llamada activa a
sumInts
. Eso disparó otra llamada recursiva, y el valor devuelto por esa llamada le devolvió la informaciónsumInts(5, 5)
. La llamada asumInts(5, 5)
entonces hizo algunos cálculos y devolvió un valor a la persona que llama.Si prueba esto con
sumInts(4, 5)
, esto es lo que sucederá:sumInts(4, 5)
intenta volver4 + sumInts(5, 5)
. Para hacer eso, llamasumInts(5, 5)
.sumInts(5, 5)
intenta volver5 + sumInts(6, 5)
. Para hacer eso, llamasumInts(6, 5)
.sumInts(6, 5)
devuelve 0 asumInts(5, 5).</li> <li>
sumInts (5, 5)now has a value for
sumInts (6, 5), namely 0. It then returns
5 + 0 = 5`.sumInts(4, 5)
ahora tiene un valor parasumInts(5, 5)
, es decir, 5. Luego regresa4 + 5 = 9
.En otras palabras, el valor que se devuelve se forma sumando los valores uno a la vez, tomando cada vez un valor devuelto por una llamada recursiva particular ay
sumInts
agregando el valor actual dea
. Cuando la recursividad toca fondo, la llamada más profunda devuelve 0. Sin embargo, ese valor no sale inmediatamente de la cadena de llamadas recursivas; en su lugar, simplemente devuelve el valor a la llamada recursiva una capa por encima. De esa manera, cada llamada recursiva simplemente agrega un número más y lo devuelve más arriba en la cadena, culminando con la suma general. Como ejercicio, intente rastrear estosumInts(2, 5)
, que es con lo que quería comenzar.¡Espero que esto ayude!
fuente
Tiene algunas buenas respuestas aquí hasta ahora, pero agregaré una más que toma un rumbo diferente.
En primer lugar, he escrito muchos artículos sobre algoritmos recursivos simples que pueden resultarle interesantes; ver
http://ericlippert.com/tag/recursion/
http://blogs.msdn.com/b/ericlippert/archive/tags/recursion/
Esos están en el orden más reciente en la parte superior, así que comience desde abajo.
En segundo lugar, hasta ahora todas las respuestas han descrito la semántica recursiva al considerar la activación de funciones . Que cada, cada llamada hace una nueva activación , y la llamada recursiva se ejecuta en el contexto de esta activación. Esa es una buena forma de pensar en ello, pero hay otra forma equivalente: buscar y reemplazar texto inteligente .
Permítame reescribir su función en una forma un poco más compacta; no piense en esto como si estuviera en un idioma en particular.
Espero que tenga sentido. Si no está familiarizado con el operador condicional, es de la forma
condition ? consequence : alternative
y su significado quedará claro.Ahora deseamos evaluar.Lo
s(2,5)
hacemos reemplazando textualmente la llamada con el cuerpo de la función, luego reemplazamosa
con2
yb
con5
:Ahora evalúe el condicional. Reemplazamos textualmente
2 > 5
confalse
.Ahora reemplace textualmente todos los condicionales falsos con la alternativa y todos los condicionales verdaderos con la consecuencia. Solo tenemos condicionales falsos, por lo que reemplazamos textualmente esa expresión con la alternativa:
Ahora, para evitar tener que escribir todos esos
+
signos, reemplace textualmente la aritmética constante con su valor. (¡Esto es un poco trampa, pero no quiero tener que hacer un seguimiento de todos los paréntesis!)Ahora busque y reemplace, esta vez con el cuerpo de la llamada,
3
paraa
y5
para b. Pondremos el reemplazo de la llamada entre paréntesis:Y ahora seguimos haciendo los mismos pasos de sustitución textual:
Todo lo que hicimos aquí fue una simple sustitución textual . Realmente no debería haber sustituido "3" por "2 + 1" y así sucesivamente hasta que tuve que hacerlo, pero pedagógicamente se habría vuelto difícil de leer.
La activación de la función no es más que reemplazar la llamada a la función con el cuerpo de la llamada y reemplazar los parámetros formales con sus argumentos correspondientes. Debe tener cuidado al introducir paréntesis de manera inteligente, pero aparte de eso, es solo un reemplazo de texto.
Por supuesto, la mayoría de los idiomas no implementan la activación como reemplazo de texto, pero lógicamente eso es lo que es.
Entonces, ¿qué es una recursividad ilimitada? ¡Una recursividad donde la sustitución textual no se detiene! Observe cómo finalmente llegamos a un paso en el que no había más
s
que reemplazar, y entonces pudimos aplicar las reglas de la aritmética.fuente
La forma en que normalmente descubro cómo funciona una función recursiva es mirando el caso base y trabajando hacia atrás. Aquí está la técnica aplicada a esta función.
Primero el caso base:
Luego, la llamada justo encima de eso en la pila de llamadas :
Luego, la llamada justo encima de eso en la pila de llamadas:
Y así:
Y así:
Observe que hemos llegado a nuestra llamada original a la función
sumInts(2, 5) == 14
El orden en el que se ejecutan estas llamadas:
El orden en el que regresan estas llamadas:
Tenga en cuenta que llegamos a una conclusión sobre cómo opera la función rastreando las llamadas en el orden en que regresan .
fuente
Voy a darle una oportunidad.
Ejecutando la ecuación a + sumInts (a + 1, b), mostraré cómo la respuesta final es 14.
Háganos saber si tiene más preguntas.
Aquí hay otro ejemplo de funciones recursivas en el siguiente ejemplo.
Un hombre acaba de graduarse de la universidad.
t es la cantidad de tiempo en años.
El número total real de años trabajados antes de jubilarse se puede calcular de la siguiente manera:
Y eso debería ser suficiente para deprimir a cualquiera, jajaja. ;-PAGS
fuente
Recursión. En Ciencias de la Computación, la recursividad se cubre en profundidad bajo el tema de Autómatas finitos.
En su forma más simple, es una autorreferencia. Por ejemplo, decir que "mi coche es un coche" es una afirmación recursiva. El problema es que la declaración es una recursividad infinita en el sentido de que nunca terminará. La definición en el enunciado de un "automóvil" es que es un "automóvil", por lo que puede ser sustituido. Sin embargo, no hay fin porque en el caso de sustitución, todavía se convierte en "mi coche es un coche".
Esto podría ser diferente si la declaración fuera "mi auto es un Bentley. Mi auto es azul". En cuyo caso, la sustitución de coche en la segunda situación podría ser "bentley", lo que resultaría en "mi bentley es azul". Estos tipos de sustituciones se explican matemáticamente en Ciencias de la Computación a través de gramáticas libres de contexto. .
La sustitución real es una regla de producción. Dado que el enunciado está representado por S y que car es una variable que puede ser un "bentley", este enunciado puede reconstruirse de forma recursiva.
Esto se puede construir de múltiples formas, ya que cada una
|
significa que hay una opción.S
se puede reemplazar por cualquiera de esas opciones, y S siempre comienza vacío. losε
medios para terminar la producción. Al igual queS
se pueden reemplazar, también se pueden reemplazar otras variables (solo hay una y esC
que representaría "bentley").Entonces, comenzando por
S
estar vacío y reemplazándolo con la primera opción"my"S
S
convierte enS
todavía se puede sustituir ya que representa una variable. Podríamos elegir "mi" de nuevo, o ε para terminarlo, pero sigamos haciendo nuestra declaración original. Elegimos el espacio que significaS
se reemplaza con" "S
A continuación, elija C
Y C solo tiene una opción de reemplazo
Y el espacio de nuevo para S
Y así sucesivamente
"my bentley is"S
,"my bentley is "S
,"my bentley is blue"S
,"my bentley is blue"
(en sustitución de S ε termina la producción) y hemos construido de forma recursiva nuestra declaración de "mi Bentley es azul".Piense en la recursividad como estas producciones y reemplazos. Cada paso del proceso reemplaza a su predecesor para producir el resultado final. En el ejemplo exacto de la suma recursiva de 2 a 5, terminas con la producción
Esto se convierte en
fuente
Creo que la mejor manera de entender las funciones recursivas es darse cuenta de que están diseñadas para procesar estructuras de datos recursivas. Pero en su función original
sumInts(a: Int, b: Int)
que calcula recursivamente la suma de números desdea
hastab
, parece no ser una estructura de datos recursiva ... Probemos una versión ligeramente modificadasumInts(a: Int, n: Int)
donden
es cuántos números agregará.Ahora, sumInts es recursivo
n
, un número natural. Aún no es un dato recursivo, ¿verdad? Bueno, un número natural podría considerarse una estructura de datos recursiva utilizando axiomas de Peano:Entonces, 0 = cero, 1 = sucesor (cero), 2 = sucesor (sucesor (cero)), y así sucesivamente.
Una vez que tenga una estructura de datos recursiva, tendrá la plantilla para la función. Para cada caso no recursivo, puede calcular el valor directamente. Para los casos recursivos , asume que la función recursiva ya está funcionando y la usa para calcular el caso, pero deconstruyendo el argumento. En el caso de Natural, significa que en lugar de
Succesor(n)
usaremosn
, o de manera equivalente, en lugar den
usaremosn - 1
.Ahora la función recursiva es más sencilla de programar. En primer lugar, el caso base,
n=0
. ¿Qué debemos devolver si no queremos sumar números? La respuesta es, por supuesto, 0.¿Qué pasa con el caso recursivo? ¿Si queremos sumar
n
números que empiecen pora
y ya tenemos unasumInts
función de trabajo que funcionen-1
? Bueno, necesitamos agregara
y luego invocarsumInts
cona + 1
, así que terminamos con:Lo bueno es que ahora no debería tener que pensar en el bajo nivel de recursividad. Solo necesita verificar que:
fuente
Puede que le interese la implementación de funciones de Nisan y Schocken . El pdf vinculado es parte de un curso en línea gratuito. Describe la segunda parte de la implementación de una máquina virtual en la que el estudiante debe escribir un compilador de lenguaje de máquina virtual a lenguaje de máquina. La implementación de la función que proponen es capaz de recursividad porque está basada en pilas.
Para presentarle la implementación de la función: considere el siguiente código de máquina virtual:
Si Swift compiló en este lenguaje de máquina virtual, entonces el siguiente bloque de código Swift:
se compilaría hasta
El lenguaje de la máquina virtual está diseñado en torno a una pila global .
push constant n
inserta un número entero en esta pila global.Después de ejecutar las líneas 1 y 2, la pila se ve así:
256
y257
son direcciones de memoria.call mult
inserta el número de línea de retorno (3) en la pila y asigna espacio para las variables locales de la función.... y va a la etiqueta
function mult
. Semult
ejecuta el código interno . Como resultado de ejecutar ese código, calculamos el producto de 2 y 3, que se almacena en la variable local 0 de la función.Justo antes de
return
ing de mult, notará la línea:Empujaremos el producto sobre la pila.
Cuando regresamos, sucede lo siguiente:
Después de regresar, estamos listos para ejecutar la línea 4, y nuestra pila se ve así:
Ahora colocamos 4 en la pila.
sub
es una función primitiva del lenguaje de la máquina virtual. Toma dos argumentos y devuelve su resultado en la dirección habitual: la del argumento 0.Ahora tenemos
Ahora que sabe cómo funciona una llamada de función, es relativamente sencillo comprender cómo funciona la recursividad. Sin magia , solo una pila.
He implementado su
sumInts
función en este lenguaje de máquina virtual:Ahora lo llamaré:
El código se ejecuta y llegamos hasta el punto de parada donde
lte
regresafalse
. Así es como se ve la pila en este punto:Ahora "desenrollemos" nuestra recursividad.
return
0 y vaya a la línea 15 y avance.Línea 16:
add
Línea 17:
return
5 y vaya a la línea 15 y avance.Línea 16:
add
Línea 17:
return
9 y vaya a la línea 15 y avance.Línea 16:
add
Línea 17:
return
12 y vaya a la línea 15 y avance.Línea 16:
add
Línea
return
17:14 y vaya a la línea 21 y avance.Ahí tienes. Recursión: glorificado
goto
.fuente
Un consejo realmente bueno que encontré al aprender y comprender realmente la recursividad es dedicar un tiempo a aprender un idioma que no tiene ninguna forma de construcción de bucle que no sea la recursividad. De esa manera, obtendrá una gran idea de cómo USAR la recursividad a través de la práctica.
Seguí http://www.htdp.org/ que, además de ser un tutorial de Scheme, también es una gran introducción sobre cómo diseñar programas en términos de arquitectura y diseño.
Pero básicamente, necesitas invertir algo de tiempo. Sin una comprensión "firme" de la recursividad, ciertos algoritmos, como el retroceso, siempre le parecerán "difíciles" o incluso "mágicos". Así que persevera. :-RE
¡Espero que esto ayude y buena suerte!
fuente
Ya hay muchas buenas respuestas. Todavía lo estoy intentando.
Cuando se llama, una función obtiene un espacio de memoria asignado, que se apila en el espacio de memoria de la función de llamada. En este espacio de memoria, la función mantiene los parámetros que se le pasan, las variables y sus valores. Este espacio de memoria desaparece junto con la llamada de retorno final de la función. Como dice la idea de pila, el espacio de memoria de de la función de llamada ahora se activa.
Para llamadas recursivas, la misma función obtiene múltiples espacios de memoria apilados uno sobre otro. Eso es todo. La simple idea de cómo funciona la pila en la memoria de una computadora debería ayudarlo a comprender cómo ocurre la recursividad en la implementación.
fuente
Un poco fuera de tema, lo sé, pero ... intente buscar la recursividad en Google ... Verá con un ejemplo lo que significa :-)
Las versiones anteriores de Google devolvieron el siguiente texto (citado de memoria):
El 10 de septiembre de 2014, se actualizó el chiste sobre la recursividad:
Para otra respuesta, vea esta respuesta .
fuente
Piense en la recursividad como múltiples clones haciendo lo mismo ...
Pides clonar [1]: "suma números entre 2 y 5"
¡¡y voilá!!
fuente
Muchas de las respuestas anteriores son muy buenas. Sin embargo, una técnica útil para resolver la recursividad es deletrear primero lo que queremos hacer y codificar como lo resolvería un humano. En el caso anterior, queremos resumir una secuencia de enteros consecutivos (usando los números de arriba):
Ahora, tenga en cuenta que estas líneas son confusas (no incorrectas, sino confusas).
¿Por qué la prueba
a>b
? Y por quéreturn 0
Cambiemos el código para reflejar más de cerca lo que hace un humano
¿Podemos hacerlo aún más humano? ¡Si! Normalmente sumamos de izquierda a derecha (2 + 3 + ...). Pero la recursividad anterior se suma de derecha a izquierda (... + 4 + 5). Cambie el código para reflejarlo (
-
puede ser un poco intimidante, pero no mucho)Algunos pueden encontrar esta función más confusa ya que estamos comenzando desde el extremo 'lejano', pero practicar puede hacer que se sienta natural (y es otra buena técnica de 'pensamiento': probar 'ambos' lados al resolver una recursividad). Y de nuevo, la función refleja lo que hace un ser humano (¿la mayoría?): Toma la suma de todos los enteros de la izquierda y suma el "siguiente" entero de la derecha.
fuente
Estaba teniendo dificultades para entender la recursividad, luego encontré este blog y ya vi esta pregunta, así que pensé que debía compartirla. Debes leer este blog, lo encontré extremadamente útil, explica con stack e incluso explica cómo dos recursiones funcionan con stack paso a paso. Le recomiendo que primero comprenda cómo funciona la pila, que se explica muy bien aquí: viaje a la pila
then now you will understand how recursion works now take a look of this post
: Comprender la recursividad paso a pasoEs un programa:
fuente
La recursividad comenzó a tener sentido para mí cuando dejé de leer lo que otros dicen al respecto o de verlo como algo que puedo evitar y simplemente escribí código. Encontré un problema con una solución e intenté duplicar la solución sin mirar. Solo miré la solución cuando me quedé atascado sin poder hacer nada. Luego volví a intentar duplicarlo. Hice esto nuevamente en múltiples problemas hasta que desarrollé mi propia comprensión y sentido de cómo identificar un problema recursivo y resolverlo. Cuando llegué a este nivel, comencé a inventar problemas y a resolverlos. Eso me ayudó más. A veces, las cosas solo se pueden aprender probándolo por su cuenta y luchando; hasta que "lo consigas".
fuente
Déjame decirte con un ejemplo de la serie de Fibonacci, Fibonacci es
así que vamos a ver cómo funciona la recursividad, acabo de reemplazar
n
ent(n)
conn-1
y así sucesivamente. parece:sabemos si
t(0)=(n-k)
es igual a1
entonces,n-k=0
asín=k
que lo reemplazamosk
conn
:si omitimos
n-n
entonces:también lo
3+2+1+(n-1)+n
es el número natural. calcula comoΣ3+2+1+(n-1)+n = n(n+1)/2 => n²+n/2
el resultado de fib es:
O(1 + n²) = O(n²)
Esta es la mejor manera de entender la relación recursiva
fuente