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 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); } }
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
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.
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:
Source: RECURSION (Java, C++) | Algorithmes et structures de données
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.
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;
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);
}
}
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.
Une solution récursive utilisant des opérateurs ternaires.
public static int fac(int n) {
return (n < 1) ? 1 : n*fac(n-1);
}
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
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.
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.
IMHO, la clé pour comprendre les actions liées à la récursion est:
func(n-1);
) qui détermine si la récursivité .__ doit aller de plus en plus loin.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.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.
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.