Module 09 · Leçon 2
Applications de la récursivité
Ce que vous saurez faire
- Écrire factorielle, puissance, palindrome en récursif
- Passer d'une formulation itérative à récursive et inversement
- Identifier les cas où la récursion est inefficace
Avant de commencer
La récursion est élégante pour les problèmes définis récursivement. Voyons des cas classiques où elle brille (et un où elle échoue).
1. Palindrome
Une chaîne est palindrome si elle se lit pareil dans les deux sens :
"laval", "radar", "", "a".
Définition récursive :
- Longueur ≤ 1 → palindrome.
- Sinon : premier caractère = dernier ET le sous-mot intérieur est palindrome.
DEF FN Palindrome(CH : chaîne) : booléen
Si Long(CH) <= 1 Alors
Palindrome ← Vrai { cas particulier (Vrai) }
Sinon Si CH[1] ≠ CH[Long(CH)] Alors
Palindrome ← Faux { cas particulier (Faux) }
Sinon
Palindrome ← FN Palindrome(Sous_chaine(CH, 2, Long(CH) - 2))
FinSi
Fin Palindrome
DEF FN Palindrome(CH : chaîne) : booléen
Si Long(CH) <= 1 Alors
Palindrome ← Vrai { cas particulier (Vrai) }
Sinon Si CH[1] ≠ CH[Long(CH)] Alors
Palindrome ← Faux { cas particulier (Faux) }
Sinon
Palindrome ← FN Palindrome(Sous_chaine(CH, 2, Long(CH) - 2))
FinSi
Fin Palindrome
FUNCTION Palindrome(ch : string) : boolean;
VAR n : integer;
BEGIN
n := Length(ch);
IF n <= 1 THEN
Palindrome := true { cas particulier (Vrai) }
ELSE IF ch[1] <> ch[n] THEN
Palindrome := false { cas particulier (Faux) }
ELSE
Palindrome := Palindrome(Copy(ch, 2, n - 2)); { récursion }
END;
Trace pour "laval" :
Palindrome("laval")→'l' = 'l'→Palindrome("ava")Palindrome("ava")→'a' = 'a'→Palindrome("v")Palindrome("v")→ longueur 1 → vrai.
2. Puissance rapide (exponentiation par carré)
base^exp :
exp = 0→ 1.exp pair→(base^(exp/2))².exp impair→base × base^(exp-1).
FUNCTION PuissRapide(base : integer; exp : integer) : longint;
VAR temp : longint;
BEGIN
IF exp = 0 THEN
PuissRapide := 1
ELSE IF exp MOD 2 = 0 THEN
BEGIN
temp := PuissRapide(base, exp DIV 2);
PuissRapide := temp * temp;
END
ELSE
PuissRapide := base * PuissRapide(base, exp - 1);
END;
Complexité : O(log exp) au lieu de O(exp). Pour 2^1000, environ
10 appels au lieu de 1000.
3. Fibonacci : le contre-exemple
FUNCTION FiboNaive(n : integer) : integer;
BEGIN
IF n < 2 THEN
FiboNaive := n
ELSE
FiboNaive := FiboNaive(n - 1) + FiboNaive(n - 2);
END;
Problème : on recalcule les mêmes valeurs exponentiellement.
FiboNaive(5) :
- F(5) appelle F(4) et F(3)
- F(4) appelle F(3) et F(2)
- F(3) appelle F(2) et F(1)
- ...
- F(3) est appelé 2 fois, F(2) 3 fois, F(1) 5 fois...
Total : environ 2^n appels. Pour n = 40, plusieurs secondes.
Solution : version itérative (vue au module 5) ou mémoïsation (stocker les valeurs déjà calculées).
4. Comparaison itératif ↔ récursif
| Aspect | Itératif | Récursif |
|---|---|---|
| Lisibilité | Souvent plus verbeuse | Souvent plus proche de la définition |
| Mémoire | O(1) (variables locales) | O(n) (pile d'appels) |
| Performance | Pas de surcoût d'appel | Surcoût léger par appel |
| Cas tordus | Plus difficile (Hanoï…) | Naturel |
5. Exercices
Écrire une fonction récursive Inverser(ch : chaîne) : chaîne qui
retourne la chaîne lue à l'envers. Indice : Inverser("abc") = Inverser("bc") + "a".
Voir le corrigé
FUNCTION Inverser(ch : string) : string;
BEGIN
IF Length(ch) <= 1 THEN
Inverser := ch
ELSE
Inverser := Inverser(Copy(ch, 2, Length(ch) - 1)) + ch[1];
END;
Réécrire SommeChiffres(n) en récursif (vu en itératif au module 2).
Indice : SommeChiffres(n) = (n mod 10) + SommeChiffres(n div 10).
Voir le corrigé
FUNCTION SommeChiffres(n : integer) : integer;
BEGIN
IF n = 0 THEN
SommeChiffres := 0
ELSE
SommeChiffres := (n MOD 10) + SommeChiffres(n DIV 10);
END;
Cas test : SommeChiffres(1234) = 4 + 3 + 2 + 1 = 10.
Écrire PGCD(a, b) en récursif en utilisant la relation d'Euclide :
PGCD(a, b) = PGCD(b, a mod b), cas de base PGCD(a, 0) = a.
Voir le corrigé
FUNCTION PGCD(a, b : integer) : integer;
BEGIN
IF b = 0 THEN
PGCD := a
ELSE
PGCD := PGCD(b, a MOD b);
END;
3 lignes. La version itérative en faisait 8. La récursive épouse exactement la définition mathématique.
6. Erreurs fréquentes au bac
- Récursion infinie : argument qui ne décroît pas.
- Cas de base manquant ou jamais atteint.
- Utiliser Fibonacci récursif naïf en croyant que c'est rapide.
- Confondre
Copy(ch, 2, n - 1)(n − 1caractères à partir du 2ème) avecCopy(ch, 2, n).
7. Quiz
Quiz (5 questions)
Pour Palindrome('aba'), combien d'appels récursifs ?
La récursion naïve de Fibonacci a une complexité :
La puissance rapide a une complexité :
Quand préférer le récursif à l'itératif ?
La mémoïsation consiste à :