La récursivité est un sujet difficile à comprendre et je ne pense pas que je peux parfaitement faire la justice ici. Au lieu de cela, je vais essayer de mettre l'accent sur le morceau de code que vous avez ici et essayer de décrire à la fois l'intuition pour expliquer pourquoi la solution des œuvres et de la mécanique 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 savoir la somme de tous les entiers de a à b, inclusivement. Pour votre exemple, vous souhaitez que la somme des nombres de 2 à 5 inclus, ce qui est
2 + 3 + 4 + 5
Lorsque vous essayez de résoudre un problème de manière récursive, l'une des premières étapes devraient être de comprendre comment diviser le problème en un petit problème avec la même structure. Donc, supposons que vous voulais résumer les nombres de 2 à 5 inclusivement. Une façon de simplifier ce qui est à remarquer que la somme ci-dessus peut être réécrite comme
2 + (3 + 4 + 5)
Ici, (3 + 4 + 5) se trouve être la somme de tous les nombres entiers compris entre 3 et 5 inclusivement. En d'autres termes, si vous voulez savoir la somme de tous les nombres entiers compris entre 2 et 5, commencez par calculer la somme de tous les nombres entiers compris entre 3 et 5, puis ajouter 2.
Alors comment faire pour calculer la somme de tous les nombres entiers compris entre 3 et 5, inclusive? Eh bien, cette somme est
3 + 4 + 5
qui peuvent être considérés plutôt comme des
3 + (4 + 5)
Ici, (4 + 5) est la somme de tous les nombres entiers compris entre 4 et 5 inclusivement. Donc, si vous voulez calculer la somme de tous les nombres compris entre 3 et 5, inclusive, vous souhaitez calculer la somme de tous les nombres entiers compris entre 4 et 5, puis ajouter 3.
Il y a un modèle ici! Si vous voulez calculer la somme des entiers compris entre a et b, inclusive, vous pouvez effectuer les opérations suivantes. Tout d'abord, calculer la somme des entiers compris entre un + 1 et b inclus. Ensuite, ajouter à ce total. Vous remarquerez que "calculer la somme des entiers compris entre un + 1 et b, inclusive" qui arrive à être à peu près le même genre de problème que nous sommes déjà en train de résoudre, mais avec un peu de paramètres différents. Plutôt que de l'informatique de a à b, inclusive, nous sommes le calcul de un + 1 pour b, inclusivement. C'est le récursive étape pour résoudre le problème le plus important ("la somme de a à b, inclusive"), on réduit le problème à une plus petite version de lui-même ("la somme de a + 1 b, inclusivement.").
Si vous regardez le code ci-dessus, vous remarquerez qu'il y a cette étape de celui-ci:
return a + sumInts(a + 1, b: b)
Ce code est simplement une traduction de la logique ci-dessus - si vous souhaitez calculer la somme de a à b, inclusive, à commencer par la somme de un + 1 pour b, inclusive (c'est l'appel récursif à l' sumInt
s), puis ajouter a
.
Bien sûr, en soi, cette approche ne fait pas travailler. Par exemple, comment voulez-vous calculer la somme de tous les nombres entiers compris entre 5 et 5 inclusivement? Eh bien, à l'aide de notre logique actuelle, vous souhaitez calculer la somme de tous les nombres entiers compris entre 6 et 5, inclusive, puis ajoutez 5. Alors comment faire pour calculer la somme de tous les nombres entiers compris entre 6 et 5, inclusive? Eh bien, à l'aide de notre logique actuelle, vous souhaitez calculer la somme de tous les nombres entiers compris entre 7 et 5 inclusivement, puis ajouter 6. Vous remarquerez un problème ici - ce qui ne cesse d'avancer et d'aller!
Dans récursifs résolution de problème, il doit y avoir un moyen d'arrêter de simplifier le problème et, au lieu de simplement aller de le résoudre directement. Généralement, vous trouverez un cas simple où la réponse peut être déterminée immédiatement, puis la structure de votre solution pour résoudre les cas les plus simples directement lorsqu'ils surviennent. Ce qui est généralement appelé un cas de base ou une récursif de base.
Quel est donc le cas de base dans ce problème particulier? Lorsque vous êtes en additionnant les nombres entiers de a à b, inclusive, si l'un se trouve être plus grand que b, alors la réponse est 0 - il n'y a pas tous les numéros de la plage! Donc, nous allons structurer notre solution comme suit:
- Si a > b, alors la réponse est 0.
- Sinon, (a ≤ b), obtenir la réponse suivante:
- Calculer la somme des entiers compris entre un + 1 et b.
- Ajouter un pour obtenir la réponse.
Maintenant, comparez cette pseudo-code de votre code:
func sumInts(a: Int, b: Int) -> Int {
if (a > b) {
return 0
} else {
return a + sumInts(a + 1, b: b)
}
}
Notez qu'il n'y a presque exactement un one-to-one de la carte entre la solution décrite dans le pseudo-code et ce code. La première étape est le cas de base - dans le cas où vous vous demandez pour la somme de vide plage de numéros, vous obtenez 0. Sinon, calculer la somme entre un + 1 et b, puis allez ajouter une.
Jusqu'à présent, j'ai donné juste un de haut niveau de l'idée derrière le code. Mais vous avez eu deux autres, très bonnes questions. Tout d'abord, pourquoi n'est-il pas toujours de retour 0, étant donné que la fonction dit de renvoyer 0 si a > b? En deuxième lieu, le 14 proviennent en réalité d'? Regardons ces facteurs à leur tour.
Essayons un très, cas très simple. Qu'advient-il si vous appelez sumInts(6, 5)
? Dans ce cas, la traçabilité par le code, vous verrez que la fonction retourne 0. C'est la bonne chose à faire, il ne sont pas tous les numéros de la plage. Maintenant, essayez quelque chose de plus difficile. Ce qui se passe lorsque vous appelez sumInts(5, 5)
? Eh bien, voici ce qui arrive:
- Vous appelez
sumInts(5, 5)
. Nous tombons dans l' else
de la branche, qui renvoie la valeur de " a + sumInts(6, 5).
- Pour
sumInts(5, 5)
afin de déterminer ce qu' sumInts(6, 5)
est, nous avons besoin de faire une pause, ce que nous faisons et faire un appel à l' sumInts(6, 5)
.
-
sumInts(6, 5)
est appelée. Il pénètre dans l' if
de la branche et les retours 0
. Toutefois, cette instance de sumInts
a été appelé par sumInts(5, 5)
, de sorte que la valeur de retour est communiquée sumInts(5, 5)
, pas de haut-niveau de l'appelant.
-
sumInts(5, 5)
peut maintenant calculer 5 + sumInts(6, 5)
de revenir 5
. Il retourne ensuite au niveau supérieur de l'appelant.
Remarquez que la valeur 5 a été formé ici. Nous avons commencé avec un appel en sumInts
. Qui a lancé un autre appel récursif, et la valeur retournée par l'appel communiqué les informations à la sumInts(5, 5)
. L'appel à l' sumInts(5, 5)
ensuite tour à tour fait un peu de calcul et a retourné une valeur de retour à l'appelant.
Si vous essayez cela avec sumInts(4, 5)
, voici ce qui va arriver:
-
sumInts(4, 5)
essaie de revenir 4 + sumInts(5, 5)
. Pour ce faire, il appelle sumInts(5, 5)
.
-
sumInts(5, 5)
essaie de revenir 5 + sumInts(6, 5)
. Pour ce faire, il appelle sumInts(6, 5)
.
-
sumInts(6, 5)
retourne 0 retour à l' 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 de sumInts(5, 5)
, à savoir 5. Il retourne alors 4 + 5 = 9
.
En d'autres termes, la valeur retournée est formé en additionnant les valeurs une par une, en prenant à chaque fois une valeur renvoyée par un appel récursif à l' sumInts
, et en ajoutant la valeur courante de a
. Lorsque la récursivité de fond, la plus profonde de l'appel renvoie 0. Cependant, cette valeur n'est pas immédiatement à la sortie de l'appel récursif de la chaîne; au lieu de cela, c'est juste les mains de la valeur de retour de l'appel récursif une couche au-dessus d'elle. De cette façon, chaque appel récursif ajoute simplement dans un plus grand nombre et renvoie plus haut dans la chaîne, culminant avec l'ensemble de la sommation. Comme exercice, essayez de suivre ce pour sumInts(2, 5)
, ce qui est ce que vous vouliez commencer avec.
Espérons que cette aide!