web-dev-qa-db-fra.com

Factorial utilisant la récursion en Java

J'apprends Java en utilisant le livre Java: la référence complète ... Je travaille actuellement sur le sujet Récursion.

S'il vous plaît noter: Il y a des questions similaires sur stackoverflow. Je les ai cherchés mais je n'ai pas trouvé la solution à ma question. Je suis confondu avec la logique du programme suivant.

Si j'exécute le programme ci-dessous, la sortie sera correcte, mais je n'ai pas compris la logique.

  • Je n'ai pas compris la logique dans la ligne suivante: result = fact (n-1) * n;
  • De ma connaissance, si nous passons la valeur de n = 4 comme indiqué dans le programme ci-dessous, 
  • Ensuite, 3 * 4 est stocké dans le résultat, à savoir 12. 
  • Encore une fois, le fait (n-1) est appelé. Alors n devient 3.
  • Ensuite, le 2 * 3 est stocké dans le résultat, remplaçant le 12 précédent.
  • Je pense que vous avez compris où je suis coincé/confus.

  • Je vous remercie.

class Calculation
{
    int fact(int n)
    {
        int result;

       if(n==1)
         return 1;

       result = fact(n-1) * n;
       return result;
    }
}

public class Factorial
{
     public static void main(String args[])
     {
       Calculation obj_one = new Calculation();

       int a = obj_one.fact(4);
       System.out.println("The factorial of the number is : " + a);
     }
}
25
user907629

result est une variable locale de la méthode fact. Ainsi, chaque fois que la méthode de faits est appelée, le résultat est stocké dans une variable différente de celle invoquée précédemment.

Donc, quand le fait est invoqué avec 3 comme argument, vous pouvez imaginer que son résultat est

 result3 = fact(2) * 3
 result3 = result2 * 3
 result3 = 1 * 2 * 3
10
JB Nizet

D'abord, vous devez comprendre comment fonctionne factorielle.

Prenons 4! par exemple.

4! = 4 * 3 * 2 * 1 = 24

Simulons le code en utilisant l'exemple ci-dessus:

int fact(int n)
    {
        int result;
       if(n==0 || n==1)
         return 1;

       result = fact(n-1) * n;
       return result;
    }

Dans la plupart des langages de programmation, nous avons ce que nous appelons function stack. C'est comme un jeu de cartes, où chaque carte est placée au-dessus de l'autre - et chaque carte peut être considérée comme une fonction. Ainsi, la méthode de transmission fact:

Niveau de pile 1: fact(4) // n = 4 and is not equal to 1. So we call fact(n-1)*n 

Niveau de pile 2: fact(3) 

Niveau de pile 3: fact(2)

Niveau de pile 4: fact(1) // now, n = 1. Nous renvoyons donc 1 à partir de cette fonction.

renvoyer des valeurs ...

Niveau de pile 3: 2 * fact(1) = 2 * 1 = 2

Niveau de pile 2: 3 * fact(2) = 3 * 2 = 6

Niveau de pile 1: 4 * fact(3) = 4 * 6 = 24

nous en avons donc eu 24.

Prenez note de ces lignes:

result = fact(n-1) * n;
           return result;

ou simplement:

return fact(n-1) * n;

Cela appelle la fonction elle-même. En utilisant 4 comme exemple,

En séquence selon les piles de fonctions.

return fact(3) * 4;
return fact(2) * 3 * 4
return fact(1) * 2 * 3 * 4

Résultats de substitution ...

return 1 * 2 * 3 * 4 = return 24

J'espère que tu as compris.

50
Neigyl R. Noval

Voici encore une autre explication du fonctionnement du calcul factoriel utilisant la récursivité.

Modifions légèrement le code source:

int factorial(int n) {
      if (n <= 1)
            return 1;
      else
            return n * factorial(n - 1);
}

Voici le calcul de 3! en détails:

 enter image description here

Source: RECURSION (Java, C++) | Algorithmes et structures de données

16
Eugene Matiyuk

Je pense que votre confusion vient du fait que vous pensez qu’il n’ya qu’une variable result alors qu’en réalité il existe une variable result pour chaque appel de fonction. Par conséquent, les anciens résultats ne sont pas remplacés, mais renvoyés.

ÉLABORER:

int fact(int n)
{
    int result;

   if(n==1)
     return 1;

   result = fact(n-1) * n;
   return result;
}

Suppose un appel à fact(2):

int result;
if ( n == 1 ) // false, go to next statement
result = fact(1) * 2; // calls fact(1):
|    
|fact(1)
|    int result;  //different variable
|    if ( n == 1 )  // true
|        return 1;  // this will return 1, i.e. call to fact(1) is 1
result = 1 * 2; // because fact(1) = 1
return 2;

J'espère que c'est plus clair maintenant.

9
Luchian Grigore

Ce qui se passe est que l'appel récursif lui-même entraîne un comportement récursif supplémentaire. Si vous deviez l'écrire, vous obtenez:

 fact(4)
 fact(3) * 4;
 (fact(2) * 3) * 4;
 ((fact(1) * 2) * 3) * 4;
 ((1 * 2) * 3) * 4;
5
rsp
public class Factorial {

    public static void main(String[] args) {
        System.out.println(factorial(4));
    }

    private static long factorial(int i) {

        if(i<0)  throw new IllegalArgumentException("x must be >= 0"); 
        return i==0||i==1? 1:i*factorial(i-1);
    }
}
5
SanA

Le point clé qui vous manque ici est que la variable "résultat" est une variable de pile et en tant que telle, elle n'est pas "remplacée". Pour élaborer, à chaque appel d'un fait, une variable NEW appelée "résultat" est créée en interne dans l'interpréteur et liée à cet appel des méthodes. Il s’agit de champs d’objets liés à l’instance de l’objet et non d’un appel de méthode spécifique.

3
idanzalz

Une solution récursive utilisant des opérateurs ternaires.

public static int fac(int n) {
    return (n < 1) ? 1 : n*fac(n-1);
}
1
martynas

Bien que ce soit vieux, il continue à arriver assez bien dans Google. Alors j'ai pensé mentionner cela. Personne n'a mentionné pour vérifier quand x = 0

0! et 1! les deux = 1. 

Cela n'est pas vérifié avec les réponses précédentes et provoquerait un débordement de pile si le fait (0) était exécuté. Quoi qu'il en soit, simple solution:

public static int fact(int x){
    if (x==1 | x==0)
        return 1;
    return fact(x-1) * x;
}// fact
1
prasanthv

Selon moi, et c’est l’opinion de quelqu'un qui connaît bien Java, je suggère de remplacer le n == 1 par n <= 1 ou (n == 0) || parce que la factorielle de 0 est 1. 

0
user3255993

Le bon est:

int factorial(int n)
{
    if(n==0||n==1)
        return 1;
    else 
        return n*factorial(n-1);
}

Cela renverrait 1 pour factoriel 0. Faites-le moi confiance. J'ai appris cela à la dure… .. Juste pour ne pas garder la condition pour 0 ne pourrait pas effacer une interview.

0
Bikram Kundu

IMHO, la clé pour comprendre les actions liées à la récursion est:

  1. Tout d'abord, nous plongeons dans la pile de manière récursive et, à chaque appel, nous modifions en quelque sorte une valeur (par exemple, n-1 in func(n-1);) qui détermine si la récursivité .__ doit aller de plus en plus loin.
  2. Une fois que RecursionStopCondition est rempli (par exemple, n == 0), les récursions s'arrêtent, Et les méthodes exécutent le travail réel et renvoient les valeurs à la méthode de l'appelant dans les piles supérieures.
  3. Il est important d'attraper la valeur renvoyée par une pile plus profonde, de façon ou d'autre. De la modifier (en la multipliant par n dans votre cas), puis de renvoyer cette valeur modifiée vers le haut de la pile. L'erreur courante est que la valeur Du cadre de pile le plus profond est renvoyée directement au sommet De la pile, de sorte que tous les appels de méthode sont ignorés.

Certes, les méthodes peuvent faire un travail utile avant de plonger dans la récursion (du haut vers le bas de la pile) ou sur le chemin du retour.

0
Konstantin

Pour le comprendre, vous devez déclarer la méthode de la manière la plus simple possible et martynas l'a clouée le 6 mai:

int fact(int n) {
    if(n==0) return 1;
    else return n * fact(n-1);
}

lisez l'implémentation ci-dessus et vous comprendrez. 

0
Eric Espino