Comme le titre l'explique, j'ai une question de programmation très fondamentale que je n'ai tout simplement pas encore pu résoudre. Filtrer tous les (extrêmement intelligents) "Pour comprendre la récursivité, vous devez d'abord comprendre la récursivité." réponses de divers fils en ligne Je ne comprends toujours pas tout à fait.
Comprenant que lorsque nous ne savons pas ce que nous ne savons pas, nous pouvons avoir tendance à poser les mauvaises questions ou à poser les bonnes questions de manière incorrecte, je vais partager ce que je "pense" ma question est dans l'espoir que quelqu'un avec des perspectives similaires puisse en partager peu de connaissances qui aideront à allumer l'ampoule récursive pour moi!
Voici la fonction (la syntaxe est écrite en Swift):
func sumInts(a: Int, b: Int) -> Int {
if (a > b) {
return 0
} else {
return a + sumInts(a: a + 1, b: b)
}
}
Nous utiliserons 2 et 5 comme arguments:
println(sumInts(a: 2, b: 5))
De toute évidence, la réponse est 14. Mais je ne sais pas exactement comment cette valeur est atteinte.
Ce sont mes 2 raccords:
La fonction est appelée récursivement jusqu'à ce qu'une condition soit remplie. Cette condition est a> b. Lorsque cette condition est remplie, retournez 0. À première vue, je m'attendrais à ce que la valeur de retour soit 0, ce qui est évidemment incorrect.
Imprimer la valeur de 'a' à chaque itération donne une valeur à laquelle je m'attendrais: 2, 3, 4, 5 (à quel point 5 + 1> b qui remplit la première condition: a> b) mais je ne le fais toujours pas ' t voir comment la valeur de 14 est atteinte.
Ma première pensée est que quelque chose de similaire à ce qui suit se passe comme par magie:
var answer = a;
answer += a+1 until a > b;
return answer;
Alors excluant la magie, je n'obtiens simplement rien. J'adorerais comprendre ce qui se passe plus qu'implicitement.
Si quelqu'un pouvait gentiment expliquer ce qui se passe techniquement pendant ce type de fonction et pourquoi le résultat n'est pas 0 et comment, finalement a + sumInts(a: a + 1, b: b) = 14
, je serais à jamais redevable.
la source
LearnYouARecursion
, des ensembles de problèmes complets de professeur de classe mondiale!Réponses:
Je pense que la confusion vient du fait que l'on pense que «la même fonction» est appelée plusieurs fois. Si vous pensez qu'il s'agit de "plusieurs copies de la même fonction appelée", cela peut être plus clair:
Une seule copie de la fonction retourne jamais 0, et ce n'est pas la première (c'est la dernière). Ainsi, le résultat de l'appel du premier n'est pas 0.
Pour la deuxième confusion, je pense qu'il sera plus facile de préciser la récursivité en anglais. Lisez cette ligne:
comme "renvoie la valeur de 'a' plus (la valeur de retour d'une autre copie de la fonction, qui est la valeur de la copie de 'a' plus (la valeur de retour d'une autre copie de la fonction, qui est la valeur de la deuxième copie de ' a 'plus (... ", chaque copie de la fonction engendrant une nouvelle copie d'elle-même avec a augmenté de 1, jusqu'à ce que la condition a> b soit remplie.
Au moment où vous atteignez la condition a> b étant vraie, vous avez une longue pile (potentiellement arbitraire) de copies de la fonction en cours d'exécution, toutes en attente du résultat de la copie suivante pour savoir ce qu'elles devrait ajouter à «a».
(edit: aussi, quelque chose à savoir, c'est que la pile de copies de la fonction que je mentionne est une chose réelle qui prend de la vraie mémoire, et plantera votre programme s'il devient trop volumineux. Le compilateur peut l'optimiser dans certains cas, mais l'épuisement de l'espace de pile est une limitation significative et malheureuse des fonctions récursives dans de nombreux langages)
la source
a
etb
.Voici ce
sumInts(2,5)
que penserait l' informatique s'il était capable de:Comme vous le voyez, certains appels à la fonction
sumInts
retournent en fait 0 mais ce n'est pas la valeur finale car l'ordinateur doit encore ajouter 5 à ce 0, puis 4 au résultat, puis 3, puis 2, comme décrit par les quatre dernières phrases de les pensées de notre ordinateur. Notez que dans la récursivité, l'ordinateur n'a pas seulement à calculer l'appel récursif, il doit également se rappeler quoi faire avec la valeur retournée par l'appel récursif. Il y a une zone spéciale de la mémoire de l'ordinateur appelée la pile où ce type d'informations est sauvegardé, cet espace est limité et des fonctions trop récursives peuvent épuiser la pile: c'est le débordement de pile qui donne son nom à notre site Web le plus aimé.Votre déclaration semble faire l'hypothèse implicite que l'ordinateur oublie ce à quoi il était lors d'un appel récursif, mais ce n'est pas le cas, c'est pourquoi votre conclusion ne correspond pas à votre observation.
Cela est dû au fait que la valeur de retour n'est pas
a
elle-même mais la somme de la valeur dea
et de la valeur renvoyée par l'appel récursif.la source
sumInts
pour qu'il écrive réellement les «pensées de l'ordinateur». Une fois que vous avez écrit une main de ces fonctions, vous l'aurez probablement «compris»!Pour comprendre la récursivité, vous devez penser le problème d'une manière différente. Au lieu d'une grande séquence logique d'étapes qui a du sens dans son ensemble, vous prenez plutôt un gros problème et le divisez en problèmes plus petits et les résolvez, une fois que vous avez une réponse pour les sous-problèmes, vous combinez les résultats des sous-problèmes pour faire le solution au plus gros problème. Pensez à vous et à vos amis qui devez compter le nombre de billes dans un énorme seau. Vous prenez chacun un seau plus petit et allez les compter individuellement et lorsque vous avez terminé, vous additionnez les totaux ensemble. Eh bien maintenant, si chacun de vous trouve un ami et divise les seaux davantage, il vous suffit d'attendre que ces autres amis calculez leurs totaux, rapportez-les à chacun de vous, additionnez-les. Etc.
Vous devez vous rappeler que chaque fois que la fonction s'appelle elle-même de manière récursive, elle crée un nouveau contexte avec un sous-ensemble du problème, une fois que cette partie est résolue, elle est renvoyée afin que l'itération précédente puisse se terminer.
Laissez-moi vous montrer les étapes:
une fois que sumInts (a: 6, b: 5) a été exécuté, les résultats peuvent être calculés afin de remonter la chaîne avec les résultats que vous obtenez:
Une autre façon de représenter la structure de la récursivité:
la source
La récursivité est un sujet délicat à comprendre et je ne pense pas pouvoir lui rendre pleinement justice ici. Au lieu de cela, je vais essayer de me concentrer sur le morceau de code particulier que vous avez ici et d'essayer de décrire à la fois l'intuition de savoir pourquoi la solution fonctionne et les mécanismes de la façon dont le code calcule son résultat.
Le code que vous avez donné ici résout le problème suivant: vous voulez connaître la somme de tous les entiers de a à b, inclus. Pour votre exemple, vous voulez la somme des nombres de 2 à 5, inclus, qui est
Lorsque vous essayez de résoudre un problème de manière récursive, l'une des premières étapes devrait être de déterminer comment décomposer le problème en un problème plus petit avec la même structure. Supposons donc que vous vouliez additionner les nombres de 2 à 5 inclus. Une façon de simplifier cela est de noter que la somme ci-dessus peut être réécrite comme
Ici, (3 + 4 + 5) se trouve être la somme de tous les nombres entiers entre 3 et 5 inclus. En d'autres termes, si vous voulez connaître la somme de tous les entiers entre 2 et 5, commencez par calculer la somme de tous les entiers entre 3 et 5, puis ajoutez 2.
Alors, comment calculez-vous la somme de tous les nombres entiers entre 3 et 5 inclus? Eh bien, cette somme est
qui peut être considéré à la place comme
Ici, (4 + 5) est la somme de tous les entiers compris entre 4 et 5 inclus. Donc, si vous vouliez calculer la somme de tous les nombres entre 3 et 5 inclus, vous calculeriez la somme de tous les nombres entiers entre 4 et 5, puis ajoutez 3.
Il y a un modèle ici! Si vous souhaitez calculer la somme des entiers entre a et b, inclus, vous pouvez effectuer les opérations suivantes. Tout d'abord, calculez la somme des entiers entre a + 1 et b, inclus. Ensuite, ajoutez un à ce total. Vous remarquerez que «calculer la somme des entiers entre a + 1 et b, inclus» se trouve être à peu près le même genre de problème que nous essayons déjà de résoudre, mais avec des paramètres légèrement différents. Plutôt que de calculer de a à b inclusivement, nous calculons de a + 1 à b inclus. C'est l'étape récursive - pour résoudre le plus gros problème ("somme de a à b, inclus"), nous réduisons le problème à une version plus petite de lui-même ("somme de a + 1 à b, inclus.").
Si vous regardez le code que vous avez ci-dessus, vous remarquerez qu'il y a cette étape dedans:
Ce code est simplement une traduction de la logique ci-dessus - si vous voulez faire la somme de a à b, inclus, commencez par additionner a + 1 à b, inclus (c'est l'appel récursif à
sumInt
s), puis ajouteza
.Bien sûr, cette approche ne fonctionnera pas en soi. Par exemple, comment calculeriez-vous la somme de tous les nombres entiers entre 5 et 5 inclus? Eh bien, en utilisant notre logique actuelle, vous calculeriez la somme de tous les nombres entiers entre 6 et 5 inclusivement, puis additionneriez 5. Alors, comment calculez-vous la somme de tous les nombres entiers entre 6 et 5 inclus? Eh bien, en utilisant notre logique actuelle, vous calculeriez la somme de tous les nombres entiers entre 7 et 5 inclusivement, puis ajoutez 6. Vous remarquerez un problème ici - cela continue et continue!
Dans la résolution de problèmes récursive, il doit y avoir un moyen d'arrêter de simplifier le problème et d'aller le résoudre directement. En règle générale, vous trouverez un cas simple où la réponse peut être déterminée immédiatement, puis structurez votre solution pour résoudre des cas simples directement lorsqu'ils surviennent. Ceci est généralement appelé un cas de base ou une base récursive .
Alors, quel est le cas de base dans ce problème particulier? Lorsque vous additionnez des entiers de a à b, inclus, si a est plus grand que b, alors la réponse est 0 - il n'y a pas de nombres dans la plage! Par conséquent, nous allons structurer notre solution comme suit:
Maintenant, comparez ce pseudocode à votre code réel:
Notez qu'il y a presque exactement une carte un-à-un entre la solution décrite dans le pseudocode et ce code réel. La première étape est le cas de base - dans le cas où vous demandez la somme d'une plage vide de nombres, vous obtenez 0. Sinon, calculez la somme entre a + 1 et b, puis ajoutez a.
Jusqu'à présent, je n'ai donné qu'une idée de haut niveau derrière le code. Mais vous aviez deux autres très bonnes questions. Premièrement, pourquoi cela ne renvoie-t-il pas toujours 0, étant donné que la fonction dit de retourner 0 si a> b? Deuxièmement, d'où viennent les 14? Regardons-les à tour de rôle.
Essayons un cas très, très simple. Que se passe-t-il si vous appelez
sumInts(6, 5)
? Dans ce cas, en suivant le code, vous voyez que la fonction renvoie simplement 0. C'est la bonne chose à faire, pour - il n'y a pas de nombres dans la plage. Maintenant, essayez quelque chose de plus difficile. Que se passe-t-il lorsque vous appelezsumInts(5, 5)
? Eh bien, voici ce qui se passe:sumInts(5, 5)
. Nous tombons dans laelse
branche, qui renvoie la valeur de `a + sumInts (6, 5).sumInts(5, 5)
de déterminer ce quesumInts(6, 5)
c'est, nous devons mettre en pause ce que nous faisons et passer un appelsumInts(6, 5)
.sumInts(6, 5)
est appelé. Il entre dans laif
succursale et revient0
. Cependant, cette instance de asumInts
été appelée parsumInts(5, 5)
, donc la valeur de retour est communiquée àsumInts(5, 5)
, et non à l'appelant de niveau supérieur.sumInts(5, 5)
maintenant peut calculer5 + sumInts(6, 5)
pour revenir5
. Il le renvoie ensuite à l'appelant de niveau supérieur.Remarquez comment la valeur 5 a été formée ici. Nous avons commencé avec un appel actif à
sumInts
. Cela a déclenché un autre appel récursif et la valeur retournée par cet appel a communiqué les informations àsumInts(5, 5)
. L'appel àsumInts(5, 5)
alors à son tour a effectué un certain calcul et renvoyé une valeur à l'appelant.Si vous essayez ceci avec
sumInts(4, 5)
, voici ce qui va se passer:sumInts(4, 5)
essaie de revenir4 + sumInts(5, 5)
. Pour ce faire, il appellesumInts(5, 5)
.sumInts(5, 5)
essaie de revenir5 + sumInts(6, 5)
. Pour ce faire, il appellesumInts(6, 5)
.sumInts(6, 5)
renvoie 0 àsumInts(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)
a maintenant une valeur poursumInts(5, 5)
, à savoir 5. Il retourne ensuite4 + 5 = 9
.En d'autres termes, la valeur renvoyée est formée en additionnant les valeurs une par une, en prenant à chaque fois une valeur renvoyée par un appel récursif particulier à
sumInts
et en ajoutant la valeur actuelle dea
. Lorsque la récursion atteint son maximum, l'appel le plus profond renvoie 0. Cependant, cette valeur ne quitte pas immédiatement la chaîne d'appels récursifs; au lieu de cela, il remet simplement la valeur à l'appel récursif un calque au-dessus. De cette façon, chaque appel récursif ajoute simplement un nombre supplémentaire et le renvoie plus haut dans la chaîne, aboutissant à la sommation globale. En tant qu'exercice, essayez de tracer celasumInts(2, 5)
, c'est ce que vous vouliez commencer.J'espère que cela t'aides!
la source
Vous avez quelques bonnes réponses ici jusqu'à présent, mais j'en ajouterai une de plus qui adopte une approche différente.
Tout d'abord, j'ai écrit de nombreux articles sur des algorithmes récursifs simples que vous pourriez trouver intéressants; voir
http://ericlippert.com/tag/recursion/
http://blogs.msdn.com/b/ericlippert/archive/tags/recursion/
Ceux-ci sont dans l'ordre le plus récent, alors commencez par le bas.
Deuxièmement, jusqu'à présent, toutes les réponses ont décrit la sémantique récursive en considérant l'activation de fonction . Que chacun, chaque appel effectue une nouvelle activation , et que l'appel récursif s'exécute dans le cadre de cette activation. C'est une bonne façon d'y penser, mais il existe une autre façon équivalente: rechercher et remplacer du texte intelligent .
Permettez-moi de réécrire votre fonction sous une forme légèrement plus compacte; ne pensez pas à cela comme étant dans une langue particulière.
J'espère que cela à du sens. Si vous n'êtes pas familier avec l'opérateur conditionnel, il est de la forme
condition ? consequence : alternative
et sa signification deviendra claire.Nous souhaitons maintenant évaluer
s(2,5)
Nous le faisons en remplaçant textuellement l'appel par le corps de la fonction, puis en remplaçanta
par2
etb
par5
:Évaluez maintenant le conditionnel. Nous remplaçons textuellement
2 > 5
parfalse
.Maintenant, remplacez textuellement toutes les fausses conditionnelles par l'alternative et toutes les vraies conditionnelles par la conséquence. Nous n'avons que de fausses conditions, nous remplaçons donc textuellement cette expression par l'alternative:
Maintenant, pour m'éviter d'avoir à taper tous ces
+
signes, remplacez textuellement l'arithmétique constante par sa valeur. (C'est un peu une triche, mais je ne veux pas avoir à garder une trace de toutes les parenthèses!)Maintenant, recherchez et remplacez, cette fois avec le corps de l'appel,
3
poura
et5
pour b. Nous mettrons le remplacement de l'appel entre parenthèses:Et maintenant, nous continuons simplement à faire ces mêmes étapes de substitution textuelle:
Tout ce que nous avons fait ici était juste une simple substitution textuelle . Vraiment, je n'aurais pas dû remplacer «3» par «2 + 1» et ainsi de suite jusqu'à ce que j'aie dû le faire, mais pédagogiquement, cela aurait été difficile à lire.
L'activation de fonction n'est rien de plus que de remplacer l'appel de fonction par le corps de l'appel, et de remplacer les paramètres formels par leurs arguments correspondants. Vous devez faire attention à l'introduction intelligente des parenthèses, mais à part cela, il ne s'agit que d'un remplacement de texte.
Bien sûr, la plupart des langues ne sont pas réellement mettre en œuvre l' activation en remplacement de texte, mais logiquement c'est ce qu'il est.
Alors, qu'est-ce qu'une récursion illimitée? Une récursion où la substitution textuelle ne s'arrête pas! Remarquez comment nous sommes finalement arrivés à une étape où il n'y avait plus rien
s
à remplacer, et nous pourrions alors simplement appliquer les règles d'arithmétique.la source
La façon dont je comprends généralement le fonctionnement d'une fonction récursive est de regarder le cas de base et de travailler à l'envers. Voici cette technique appliquée à cette fonction.
Tout d'abord le cas de base:
Ensuite, l'appel juste au-dessus dans la pile d'appels :
Ensuite, l'appel juste au-dessus dans la pile d'appels:
Etc:
Etc:
Notez que nous sommes arrivés à notre appel initial à la fonction
sumInts(2, 5) == 14
L'ordre dans lequel ces appels sont exécutés:
L'ordre dans lequel ces appels reviennent:
Notez que nous sommes arrivés à une conclusion sur le fonctionnement de la fonction en traçant les appels dans l'ordre dans lequel ils retournent .
la source
Je vais essayer.
En exécutant l'équation a + sumInts (a + 1, b), je vais montrer comment la réponse finale est 14.
Faites-nous savoir si vous avez d'autres questions.
Voici un autre exemple de fonctions récursives dans l'exemple suivant.
Un homme vient de terminer ses études collégiales.
t est la durée en années.
Le nombre total réel d'années travaillées avant la retraite peut être calculé comme suit:
Et cela devrait suffire à déprimer n'importe qui, lol. ;-P
la source
Récursivité. En informatique, la récursivité est traitée en profondeur sous le thème des automates finis.
Dans sa forme la plus simple, c'est une auto-référence. Par exemple, dire que "ma voiture est une voiture" est une déclaration récursive. Le problème est que l'instruction est une récursion infinie en ce qu'elle ne finira jamais. La définition dans l'énoncé d'une «voiture» est qu'il s'agit d'une «voiture» et peut donc être remplacée. Cependant, il n'y a pas de fin car en cas de substitution, cela devient quand même "ma voiture est une voiture".
Cela pourrait être différent si la déclaration était "ma voiture est une bentley. Ma voiture est bleue". Dans ce cas, la substitution dans la deuxième situation pour la voiture pourrait être "bentley" résultant en "ma bentley est bleue". Ces types de substitutions sont expliqués mathématiquement en informatique par des grammaires sans contexte .
La substitution réelle est une règle de production. Étant donné que l'énoncé est représenté par S et que la voiture est une variable qui peut être un «bentley», cet énoncé peut être reconstruit de manière récursive.
Cela peut être construit de plusieurs manières, car chacune
|
signifie qu'il y a un choix.S
peut être remplacé par n'importe lequel de ces choix, et S commence toujours vide. Lesε
moyens de mettre fin à la production. Tout commeS
peuvent être remplacées, d'autres variables peuvent l'être également (il n'y en a qu'une etC
ce qui représenterait "bentley").Donc commencer par
S
être vide, et le remplacer par le premier choix"my"S
S
devientS
peut toujours être substitué car il représente une variable. Nous pourrions choisir à nouveau "mon", ou ε pour le terminer, mais continuons à faire notre déclaration originale. Nous choisissons l'espace qui signifieS
est remplacé par" "S
Ensuite, choisissons C
Et C n'a qu'un seul choix pour le remplacement
Et de nouveau l'espace pour S
Et ainsi de suite
"my bentley is"S
,"my bentley is "S
,"my bentley is blue"S
,"my bentley is blue"
(remplaçant S pour ε se termine la production) et nous avons construit notre récursive déclaration « mon bentley est bleu ».Pensez à la récursivité comme à ces productions et remplacements. Chaque étape du processus remplace son prédécesseur afin de produire le résultat final. Dans l'exemple exact de la somme récursive de 2 à 5, vous vous retrouvez avec la production
Cela devient
la source
Je pense que la meilleure façon de comprendre les fonctions récursives est de réaliser qu'elles sont conçues pour traiter des structures de données récursives. Mais dans votre fonction d'origine
sumInts(a: Int, b: Int)
qui calcule récursivement la somme des nombres dea
àb
, cela ne semble pas être une structure de données récursive ... Essayons une version légèrement modifiéesumInts(a: Int, n: Int)
oùn
est le nombre de nombres que vous ajouterez.Maintenant, sumInts est récursif sur
n
, un nombre naturel. Toujours pas une donnée récursive, non? Eh bien, un nombre naturel pourrait être considéré comme une structure de données récursive utilisant les axiomes Peano:Donc, 0 = zéro, 1 = successeur (zéro), 2 = successeur (successeur (zéro)), et ainsi de suite.
Une fois que vous avez une structure de données récursive, vous avez le modèle pour la fonction. Pour chaque cas non récursif, vous pouvez calculer la valeur directement. Pour les cas récursifs, vous supposez que la fonction récursive fonctionne déjà et vous l'utilisez pour calculer le cas, mais en déconstruisant l'argument. Dans le cas de Natural, cela signifie qu'au lieu de
Succesor(n)
nous utiliseronsn
, ou de manière équivalente, au lieu den
nous utiliseronsn - 1
.Désormais, la fonction récursive est plus simple à programmer. Tout d' abord, le cas de base,
n=0
. Que devons-nous retourner si nous ne voulons ajouter aucun chiffre? La réponse est bien sûr 0.Qu'en est-il du cas récursif? Si nous voulons ajouter des
n
nombres commençant para
et nous avons déjà unesumInts
fonction de travail qui fonctionne pourn-1
? Eh bien, nous devons ajoutera
puis invoquersumInts
aveca + 1
, donc nous finissons par:La bonne chose est que maintenant vous ne devriez pas avoir besoin de penser au faible niveau de récursivité. Il vous suffit de vérifier que:
la source
Vous pourriez être intéressé par l' implémentation des fonctions de Nisan et Schocken . Le pdf lié fait partie d'un cours en ligne gratuit. Il décrit la deuxième partie d'une implémentation de machine virtuelle dans laquelle l'étudiant doit écrire un compilateur de langage de machine virtuelle à langage de machine. L'implémentation de fonction qu'ils proposent est capable de récursivité car elle est basée sur la pile.
Pour vous présenter l'implémentation de la fonction: Considérez le code de machine virtuelle suivant:
Si Swift compilé dans ce langage de machine virtuelle, alors le bloc suivant de code Swift:
compilerait jusqu'à
Le langage de la machine virtuelle est conçu autour d'une pile globale .
push constant n
pousse un entier sur cette pile globale.Après avoir exécuté les lignes 1 et 2, la pile ressemble à:
256
et257
sont des adresses de mémoire.call mult
pousse le numéro de la ligne de retour (3) sur la pile et alloue de l'espace pour les variables locales de la fonction.... et ça va au label
function mult
. Le code à l'intérieurmult
est exécuté. À la suite de l'exécution de ce code, nous calculons le produit de 2 et 3, qui est stocké dans la 0ème variable locale de la fonction.Juste avant
return
d'entrer de mult, vous remarquerez la ligne:Nous allons pousser le produit sur la pile.
À notre retour, ce qui suit se produit:
Après le retour, nous sommes prêts à exécuter la ligne 4, et notre pile ressemble à ceci:
Maintenant, nous poussons 4 sur la pile.
sub
est une fonction primitive du langage de la machine virtuelle. Il prend deux arguments et renvoie son résultat à l'adresse habituelle: celle du 0ème argument.Maintenant nous avons
Maintenant que vous savez comment fonctionne un appel de fonction, il est relativement simple de comprendre le fonctionnement de la récursivité. Pas de magie , juste une pile.
J'ai implémenté votre
sumInts
fonction dans ce langage de machine virtuelle:Maintenant, je vais l'appeler:
Le code s'exécute et nous arrivons jusqu'au point d'arrêt où
lte
revientfalse
. Voici à quoi ressemble la pile à ce stade:Maintenant, "déroulons" notre récursivité.
return
0 et aller à la ligne 15 et avancer.Ligne 16:
add
Ligne 17:
return
5 et aller à la ligne 15 et avancer.Ligne 16:
add
Ligne 17:
return
9 et aller à la ligne 15 et avancer.Ligne 16:
add
Ligne
return
17:12 et aller à la ligne 15 et avancer.Ligne 16:
add
Ligne
return
17:14 et aller à la ligne 21 et avancer.Voilà. Récursivité: glorifiée
goto
.la source
Un très bon conseil que j'ai rencontré en apprenant et en comprenant vraiment la récursivité est de passer du temps à apprendre un langage qui n'a aucune forme de construction de boucle autre que la récursivité. De cette façon, vous aurez une bonne idée de la façon d'utiliser la récursivité via la pratique.
J'ai suivi http://www.htdp.org/ qui, en plus d'être un didacticiel Scheme, est également une excellente introduction sur la façon de concevoir des programmes en termes d'architecture et de design.
Mais fondamentalement, vous devez investir du temps. Sans une compréhension «ferme» de la récursivité, certains algorithmes, comme le retour en arrière, vous sembleront toujours «difficiles», voire «magiques». Alors, persévérez. :-RÉ
J'espère que ça aide et bonne chance!
la source
Il y a déjà beaucoup de bonnes réponses. Je suis encore en train d'essayer.
Lorsqu'elle est appelée, une fonction obtient un espace mémoire alloué, qui est empilé sur l' espace mémoire de la fonction appelante. Dans cet espace mémoire, la fonction conserve les paramètres qui lui sont passés, les variables et leurs valeurs. Cet espace mémoire disparaît avec l'appel de retour de fin de la fonction. Comme l'idée de pile va, l' espace mémoire de la fonction appelant devient maintenant actif.
Pour les appels récursifs, la même fonction obtient plusieurs espaces mémoire empilés les uns sur les autres. C'est tout. L'idée simple du fonctionnement de la pile dans la mémoire d'un ordinateur devrait vous permettre de comprendre comment la récursivité se produit dans l'implémentation.
la source
Un peu hors sujet, je sais, mais ... essayez de rechercher la récursivité dans Google ... Vous verrez par exemple ce que cela signifie :-)
Les versions antérieures de Google ont renvoyé le texte suivant (cité de mémoire):
Le 10 septembre 2014, la blague sur la récursivité a été mise à jour:
Pour une autre réponse, voir cette réponse .
la source
Pensez à la récursivité comme à plusieurs clones faisant la même chose ...
Vous demandez de cloner [1]: "somme des nombres entre 2 et 5"
et voilá !!
la source
Bon nombre des réponses ci-dessus sont très bonnes. Cependant, une technique utile pour résoudre la récursivité consiste à définir d'abord ce que nous voulons faire et à coder comme un humain le résoudrait. Dans le cas ci-dessus, nous voulons résumer une séquence d'entiers consécutifs (en utilisant les nombres ci-dessus):
Maintenant, notez que ces lignes sont déroutantes (pas fausses, mais déroutantes).
Pourquoi le test
a>b
?, Et pourquoireturn 0
Changeons le code pour refléter plus étroitement ce que fait un humain
Pouvons-nous le faire encore plus humainement? Oui! Habituellement, nous résumons de gauche à droite (2 + 3 + ...). Mais la récursion ci-dessus est la somme de droite à gauche (... + 4 + 5). Changer le code pour le refléter (Cela
-
peut être un peu intimidant, mais pas beaucoup)Certains peuvent trouver cette fonction plus déroutante car nous partons de l'extrémité `` éloignée '', mais la pratique peut la rendre naturelle (et c'est une autre bonne technique de `` réflexion '': essayer les `` deux '' côtés lors de la résolution d'une récursivité). Et encore une fois, la fonction reflète ce que fait un humain (le plus?): Prend la somme de tous les entiers de gauche et ajoute le «prochain» entier à droite.
la source
J'avais du mal à comprendre la récursivité alors j'ai trouvé ce blog et j'ai déjà vu cette question alors j'ai pensé que je devais partager. Vous devez lire ce blog, j'ai trouvé cela extrêmement utile, il explique avec pile et même il explique comment deux récursions fonctionnent avec la pile étape par étape. Je vous recommande d'abord de comprendre le fonctionnement de la pile, ce que cela explique très bien ici: Journey-to-the-stack
then now you will understand how recursion works now take a look of this post
: Comprendre la récursivité étape par étapeC'est un programme:
la source
La récursivité a commencé à avoir un sens pour moi lorsque j'ai arrêté de lire ce que les autres en disent ou que je la vois comme quelque chose que je peux éviter et que j'écris du code. J'ai trouvé un problème avec une solution et j'ai essayé de dupliquer la solution sans chercher. Je n'ai regardé la solution que lorsque je suis resté impuissant. Puis je suis retourné à essayer de le dupliquer. Je l'ai fait à nouveau sur plusieurs problèmes jusqu'à ce que je développe ma propre compréhension et mon sens de la façon d'identifier un problème récursif et de le résoudre. Quand je suis arrivé à ce niveau, j'ai commencé à inventer des problèmes et à les résoudre. Cela m'a aidé davantage. Parfois, les choses ne peuvent être apprises qu'en essayant par vous-même et en luttant; jusqu'à ce que vous «compreniez».
la source
Laissez-moi vous dire avec un exemple de la série Fibonacci, Fibonacci est
donc permettre de voir comment fonctionne récursives, je remplace simplement
n
ent(n)
avecn-1
et ainsi de suite. ça ressemble:nous savons si
t(0)=(n-k)
égaux à1
alorsn-k=0
sin=k
nous remplaçonsk
avecn
:si nous omettons
n-n
alors:il en
3+2+1+(n-1)+n
est de même pour le nombre naturel. il se calcule commeΣ3+2+1+(n-1)+n = n(n+1)/2 => n²+n/2
le résultat pour fib est:
O(1 + n²) = O(n²)
C'est la meilleure façon de comprendre la relation récursive
la source