Une fonction ou plus généralement un algorithme qui contient un appel à elle-même est dite récursive. Deux fonctions peuvent s'appeler l'une l'autre, on parle alors de récursivité croisée.
public static int fact(int n) { if (n <= 1) { return 1; } else { return n * fact(n - 1); } }
Attention : considérons la fonction suivante :
public static int f(int i) { return i * f(i - 1); }
Quelle est la valeur de l'appel f(3) ?
Un problème !
Exception in thread "main" java.lang.StackOverflowError
Que se passe-t-il ?
Des milions d'appels, chacun ayant besoin d'un espace mémoire pour les valeurs des paramètres de la fonction et de possibles variables locales (cet espace est appelé la pile d'exécution).
Remède : similairement aux boucles, on doit avoir une condition d'arrêt pour éviter les appels récursifs infinis.
fact(1) | 1 | ? | fact(1) | 1 | 1 | ||||||||||||||||||
fact(2) | 2 | ? | fact(2) | 2 | ? | fact(2) | 2 | ? | fact(2) | 2 | 2 | ||||||||||||
fact(3) | 3 | ? | fact(3) | 3 | ? | fact(3) | 3 | ? | fact(3) | 3 | ? | fact(3) | 3 | ? | fact(3) | 3 | 6 | ||||||
fact(4) | 4 | ? | fact(4) | 4 | ? | fact(4) | 4 | ? | fact(4) | 4 | ? | fact(4) | 4 | ? | fact(4) | 4 | ? | fact(4) | 4 | ? | fact(4) | 4 | 24 |
n | fact | n | fact | n | fact | n | fact | n | fact | n | fact | n | fact | n | fact |
La fonction factorielle présentée de manière récursive, peut être codée sous forme d'une itération :
final int N = 5; int fact = 1; for (int i=2; i<=N; i++) fact *= i;
while
, for
, do/while
); la récursivité utilise des appels et l'instruction if
Il y a 3 tours; la première porte n disques de tailles toutes différentes, empilés du plus grand (en bas) au plus petit (en haut). Le problème consiste à faire passer tous ces disques à la tour 2, en s'aidant de la troisième tour, en respectant les règles suivantes :
Plusieurs visualisations sur le Web :
un algorithme récursif :
Soit : nombre : nombre de disques utilisés de : emplacement de départ à : emplacement de destination par : emplacement intermédiaire déplacer (nombre, de, à, par) si nombre > 0 alors déplacer nombre - 1, de, par, à; bouger-un-disque de, à; déplacer nombre - 1, par, à, de;
Codez ce programme en Java. Les appels de "bouger-un-disque" seront affichés sous la forme suivante (pour nombre = 3) :
1 --> 3 1 --> 2 3 --> 2 1 --> 3 2 --> 1 2 --> 3 1 --> 3
Modifiez votre programme pourqu'il compte le nombre de déplacements de disque.