Objectif général
Résoudre des problèmes définis récursivement.
I. Notion de récursivité
I.1 Définition
La récursivité est un concept très puissant si on arrive à décomposer un problème en un ou plusieurs
sous-problèmes qui sont de même nature. Il est de même quand on décompose un objet en groupes
de composants qui présentent les mêmes propriétés et qui ne contiennent qu'un sous-ensemble de
l'objet. Une notion est dite récursive si elle, entre, elle même dans sa composition ou dans sa
définition.
Exemples
« Mon ascendant est mon père, ma mère ou un de leurs ascendants »
De même, un algorithme est dit récursif s’il fait appel à lui-même. Ainsi, la fonction factorielle :
n! = (n-1)! * n
Cette expression ne fait que déplacer le problème de l’ordre n à l’ordre n-1, sans le résoudre. Par
bonheur, en faisant ainsi décroître l’ordre, on parvient à une relation sans indétermination : 1! = 1
(ou éventuellement (0 ! = 1). Grâce à cette propriété, le traitement récursif de la factorielle n’est pas
un cercle vicieux. Son algorithme s’écrit :
Les entiers naturels sont définis d’une manière récursive par deux règles :
0 est un entier naturel.
Le successeur d'un entier naturel est un entier naturel.
La définition récurrente des suites mathématiques :
U0 = 1
Un = aUn-1 + b
Les chaînes de caractères sont définies récursivement -Une chaîne de caractères est soit :
Une chaîne vide, soit,
Un caractère suivi d'une chaîne.
n=1
n=2 n=2 n=2
n=3 n=3 n=3 n=3 n=3
Etat initial (a) (b) (c) (d) (e) Etat final
(a) Premier appel de Factorielle (3), on affecte au paramètre n la valeur 3. Comme (n > 1) on calcule
n * Factorielle (n-1) : n = 3, n-1 = 2 on appelle alors Factorielle (2)
(b) Deuxième appel, n prend la valeur 2, n >1, on appelle Factorielle (1)
(c) Troisième appel, on affecte à n la valeur 1, la condition (n>1) n’est plus vérifiée, donc on quitte
la fonction, on libère la pile de son sommet, on retourne où la fonction Factorielle (1) a été
appelée en retournant la valeur 1.
(d) on peut maintenant calculer n * Factorielle (1), n (sommet de la pile) vaut 2, Factorielle (1) vaut
1, on peut retourner 2, puis on dépile n.
(e) on peut calculer n * Factorielle (2), n vaut 3 (sommet de la pile), Factorielle (2) vaut 2, 3 * 2 = 6,
on retourne 6, la pile est vidée et retrouve son état initial.
Notion d'environnement : Il est formé par l'ensemble de données (variables et paramètres)
utilisées par un module lors d'une exécution. Chaque fois que le module est appelé
récursivement, un nouvel environnement est généré, un nouvel ensemble de variables locales et
de paramètres est créé. Bien qu'elles portent le même nom que celles créées à l'appel précédent,
leurs valeurs sont différentes et on utilise toujours le dernier jeu de variables créé. Cet
environnement est détruit lorsque l'exécution prend fin.
Si un module appelle un autre module sans que son exécution ne soit terminée, l'environnement
du premier est suspendu et il sera réactivé lorsque l'exécution du second sera terminée.
L’ensemble des environnements existant pour une exécution (suspendus ou actif) forme ce qu’on
appelle une pile d’environnement.
Terminaison : Les traitements engendrés par une définition récursive doivent être finis pour que
le calcul puisse se terminer. Tout appel récursif doit donc contenir une clause conditionnelle telle
que l'évaluation puisse dans certains cas se faire sans récursivité. Dans le cas de la fonction
Factorielle(n), la condition d’arrêt est : n ≤ 1.
Valeur d'arrêt : C'est la valeur pour laquelle les appels récursifs s'arrêtent. Pour le cas de
Factorielle (n), la valeur d'arrêt est n = 1.
Profondeur : Dans la plupart des cas, la récursivité est appliquée à une valeur entière qui diminue
d'une unité à chaque exécution. Dans ce cas, si on considère fi cette valeur lors du premier appel
et ft cette même valeur à la terminaison, on dit que la récursivité est de profondeur (fi – ft).
La profondeur indique le nombre de niveaux de récursivité, c’est à dire le nombre
d’environnements qui peuvent être suspendus en même temps. Par exemple, pour la fonction
Factorielle (3), la profondeur est égale à 2.
Exemple :
La suite de Fibbonacci est définie comme suit pour tout n 0 :
F(0) = 0, F(1) = 1
F(n) = F(n-2) + F(n-1) pour n >1
Exemple
Soit la fonction d'Ackermann définie pour tous les entiers positifs m et n de la manière suivante :
Acker (0,n) = n + 1
Acker (m,0) = Acker (m-1,1) pour m 1
Acker (m,n) = Acker(m-1, Acker (m,n-1)) pour m 1 et n 1
III.3. Algorithme
La solution algorithmique est sous forme d’une procédure qui se présente comme suit :
Procédure Hanoi (Don n : Entier ; Don A : Chaîne, Don B : Chaîne, Don C : Chaîne)
--Précond : n 1
Début
Si (n = 1) Alors
Ecrire ("Déplacer un disque de ", A, " vers ", C)
Sinon
Hanoi (n-1, A, C, B)
Ecrire ("Déplacer un disque de ", A, " vers ", C)
Hanoi (n-1, B, A, C)
FinSi
Fin
Dans ce qui suit, voici un exemple d’exécution de cette procédure pour :
Hanoi (3, "Piquet A", "Piquet B", "Piquet C")