80 votes

Comment "fonctionne" la fonction récursive de Fibonacci ?

Je suis novice en Javascript et j'étais en train de me documenter sur le sujet, lorsque je suis arrivé à un chapitre décrivant la récursion des fonctions. Il utilisait une fonction d'exemple pour trouver le nième nombre de la séquence de Fibonacci. Le code est le suivant :

function fibonacci(n) {
    if (n < 2){
        return 1;
    }else{
        return fibonacci(n-2) + fibonacci(n-1);
    }
}

console.log(fibonacci(7));
//Returns 21

J'ai du mal à comprendre ce que fait exactement cette fonction. Quelqu'un peut-il m'expliquer ce qui se passe ici ? Je suis bloqué à la 5e ligne, où la fonction s'appelle elle-même. Que se passe-t-il ici ?

117voto

lwburk Points 29313

Vous définissez une fonction en fonction d'elle-même. En général, fibonnaci(n) = fibonnaci(n - 2) + fibonnaci(n - 1) . Nous ne faisons que représenter cette relation en code. Ainsi, pour fibonnaci(7) que nous pouvons observer :

  • fibonacci(7) est égal à fibonacci(6) + fibonacci(5)
  • fibonacci(6) est égal à fibonacci(5) + fibonacci(4)
  • fibonacci(5) est égal à fibonacci(4) + fibonacci(3)
  • fibonacci(4) est égal à fibonacci(3) + fibonacci(2)
  • fibonacci(3) est égal à fibonacci(2) + fibonacci(1)
  • fibonacci(2) est égal à fibonacci(1) + fibonacci(0)
  • fibonacci(1) est égal à 1
  • fibonacci(0) est égal à 1

Nous avons maintenant toutes les pièces nécessaires pour évaluer fibonacci(7) ce qui était notre objectif initial. Remarquez que le cas de base -- return 1 quand n < 2 -- est ce qui rend cela possible. C'est ce qui arrête la récursion, de sorte que nous pouvons commencer le processus de déroulement de la pile et d'addition des valeurs que nous retournons à chaque étape. Sans cette étape, nous continuerions à appeler fibonacci sur des valeurs de plus en plus petites jusqu'à ce que le programme s'arrête.

Il pourrait être utile d'ajouter quelques déclarations d'enregistrement qui illustrent cela :

function fibonacci(n, c) {
    var indent = "";
    for (var i = 0; i < c; i++) {
        indent += " ";
    }
    console.log(indent + "fibonacci(" + n + ")");
    if (n < 2) {
        return 1;
    } else {
        return fibonacci(n - 2, c + 4) + fibonacci(n - 1, c + 4);
    }
}

console.log(fibonacci(7, 0));

Sortie :

fibonacci(7)
    fibonacci(5)
        fibonacci(3)
            fibonacci(1)
            fibonacci(2)
                fibonacci(0)
                fibonacci(1)
        fibonacci(4)
            fibonacci(2)
                fibonacci(0)
                fibonacci(1)
            fibonacci(3)
                fibonacci(1)
                fibonacci(2)
                    fibonacci(0)
                    fibonacci(1)
    fibonacci(6)
        fibonacci(4)
            fibonacci(2)
                fibonacci(0)
                fibonacci(1)
            fibonacci(3)
                fibonacci(1)
                fibonacci(2)
                    fibonacci(0)
                    fibonacci(1)
        fibonacci(5)
            fibonacci(3)
                fibonacci(1)
                fibonacci(2)
                    fibonacci(0)
                    fibonacci(1)
            fibonacci(4)
                fibonacci(2)
                    fibonacci(0)
                    fibonacci(1)
                fibonacci(3)
                    fibonacci(1)
                    fibonacci(2)
                        fibonacci(0)
                        fibonacci(1)

Les valeurs situées au même niveau d'indentation sont additionnées pour produire le résultat du niveau d'indentation précédent.

40voto

Jeff Callahan Points 126

Il y a beaucoup de bonnes réponses ici, mais j'ai fait ce diagramme qui aide à mieux expliquer le résultat de la fonction. Les seules valeurs qui seront retournées sont 1 ou 0 (votre exemple retourne 1 pour n < 2, mais devrait plutôt retourner n).

Cela signifie que chaque appel récursif finira par retourner un 0 ou un 1. Ceux-ci finissent par être "mis en cache" dans la pile et "reportés" dans l'invocation originale et additionnés.

Ainsi, si vous deviez dessiner ce même diagramme pour chaque valeur de "n", vous pourriez trouver la réponse manuellement.

Ce diagramme illustre grossièrement comment chaque fonction est retournée pour fib(5).

! Fibonacci Javascript Tree Diagram

Cela montre le flux de contrôle, c'est-à-dire l'ordre d'exécution des fonctions. Rappelez-vous que le code est toujours exécuté de gauche à droite et de haut en bas. Ainsi, chaque fois qu'une nouvelle fonction est appelée, elle est mise en pause, puis l'invocation suivante a lieu.

Ce qui suit illustre le flux de contrôle réel basé sur votre message original. Veuillez noter que la condition de base est if (n <= 0) {return 0} else if (n <= 2) {return 1;} par souci de simplification :

1. fib(5) {
    return fib(4) + fib(3);
2.   fib(4) {
      return fib(3) + fib(2);
3.     fib(3) {
        return fib(2) + fib(1);
4.       fib(2) {
A=        return 1;
         };
5.       fib(1) {
B=        return 1;
         };
C=      return 2; // (1 + 1)
       };
6.     fib(2) {
D=      return 1;
       };
E=    return 3; // (2 + 1)
     };
7.   fib(3) {
      return fib(2) + fib(1);
8.     fib(2) {
F=      return 1;
       };
9.     fib(1) {
G=      return 1;
       };
H=    return 2; // (1 + 1)
     };
I=  return 5; // (3 + 2)
   };

25voto

Jesse Good Points 22971

Étape 1) Lorsque fibonacci(7) est appelé imaginez ce qui suit (remarquez comment j'ai changé tous les n en 7) :

function fibonacci(7) {
    if (7 < 2){
        return 1;
    }else{
        return fibonacci(7-2) + fibonacci(7-1);
    }
}

Étape 2) Puisque (7 < 2) est manifestement faux, nous passons à fibonacci(7-2) + fibonacci(7-1); ce qui se traduit par fibonacci(5) + fibonacci(6); Depuis fibonacci(5) vient en premier, qui est appelé (change les n en 5 cette fois) :

function fibonacci(5) {
    if (5 < 2){
        return 1;
    }else{
        return fibonacci(5-2) + fibonacci(5-1);
    }
}

Étape 3) Et ou cours fibonacci(6) est également appelé, donc ce qui se passe, c'est que pour chaque appel de fibonacci 2 nouveaux fibonacci être appelé.

Visualisation :

      fibonacci(7)
      ____|_____
     |          |
fibonacci(5)  fibonacci(6)
____|____     ____|_____
|        |    |         |
fib(3)  fib(4) fib(4)   fib(5)

Tu vois comment ça se ramifie ? Quand est-ce que ça va s'arrêter ? Quand n devient inférieur à 2, c'est pourquoi vous avez if (n < 2) . À ce moment-là, les ramifications s'arrêtent et tout s'additionne.

8voto

RobG Points 41170

J'espère que ce qui suit vous aidera. Appeler :

fibonacci(3)

arrivera à la ligne 5 et fera :

return fibonacci(1) + fibonacci(2);

la première expression appelle à nouveau la fonction et renvoie 1 (puisque n < 2 ).

Le second appelle à nouveau la fonction, arrive à la 5ème ligne et fait :.

return fibonacci(0) + fibonacci(1);

les deux expressions renvoient 1 (puisque n < 2 pour les deux), donc cet appel à la fonction renvoie 2.

La réponse est donc 1 + 2, ce qui donne 3.

3voto

Sl4rtib4rtf4st Points 420

Ces deux fonctions m'ont permis d'avoir une explication beaucoup plus claire de la récursion (de cette article de blog ):

function fibDriver(n) {
  return n === 0 ? 0 : fib(0, 1, n);
}

function fib(a, b, n) {
  return n === 1 ? b : fib(b, a + b, n-1);
}

// Get the 10th fibbonacci number (when excluding the 0)
console.log(fibDriver(10))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X