Pile d'appels☘
Pour illustrer les exemples de cette partie, nous allons utiliser la
fonction rectangle() définie comme suit :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
Ordre des appels récursifs☘
Dans une fonction récursive, l'ordre d'exécution des instructions dépend des appels récursifs à la fonction. En d'autres termes, certaines instructions peuvent être exécutées immédiatement tandis que d'autres sont « mises en attente » dans une pile d'appels.
Un premier exemple☘
On considère la fonction récursive suivante :
17 18 19 20 21 22 23 | |
On effectue l'appel fct1(50). Complétez la pile d'appel puis tracez la
figure correspondante.

Le programme complet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
Réponses
Le rectangle est tracé avant l'appel récursif suivant :

On en déduit le dessin suivant pour l'appel fct1(50)

Un second exemple☘
On échange les instructions des lignes 22 et 23 pour définir la fonction
récursive suivante :
17 18 19 20 21 22 23 | |
On effectue l'appel fct2(50). Complétez la pile d'appel puis tracez la
figure correspondante.

Le programme complet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
Réponses
Lorsqu'on exécute fct2(50) :
- On exécute
fct2(40)donc on met en attenterectangle(50); - On exécute
fct2(30)donc on met en attenterectangle(40)en priorité devantrectangle(50)carfct2(40)doit être exécuté avantrectangle(50); - On exécute
fct2(20)donc on met en attenterectangle(30)en priorité devantrectangle(40)en priorité devantrectangle(50); - On exécute
fct2(10)donc on met en attenterectangle(20)en priorité devantrectangle(30)en priorité devantrectangle(40)en priorité devantrectangle(50); 10n'est pas strictement supérieur à10, les appels se terminent.- On dépile par ordre de priorité en traçant dans l'ordre
rectangle(20),rectangle(30),rectangle(40)puisrectangle(50)
L'illustration ci-dessous permet de mieux visualiser l'empilement de
ces appels :

On en déduit le dessin suivant pour l'appel fct2(50)

Complexité☘
Rappel
La complexité d'un algorithme se décompose généralement sous deux formes :
-
La complexité en temps : combien de temps prend un algorithme pour s'exécuter ?
On ramène généralement cette question au décompte du nombre d'opérations élémentaires nécessaires pour le déroulement de l'algorithme. -
La complexité en mémoire : quel espace en mémoire est nécessaire au déroulement de l'algorithme ?
On notera généralement n le nombre de données à traiter. La complexité est ensuite donnée comme un « ordre de grandeur » de n. Cet ordre de grandeur est souvent noté O (se lit « grand O ») :
| Classe de complexité | Type de complexité |
|---|---|
| O(1) | constante |
| O(log(n)) | logarithmique |
| O(n) | linéaire |
| O(n × log(n)) | quasi-linéaire |
| O(n²) | quadratique |
| O(2n) | exponentielle |
| O(n!) | factorielle |
Pour les fonctions récursives envisagées ci-dessous, on admet que la complexité en temps est proportionnelle au nombre d'appels récursifs.
Un premier exemple☘
On considère la fonction récursive suivante :
1 2 3 4 5 6 | |
- Combien d'appels à la fonction
descente()sont réalisés lorsqu'on exécute l'instructiondescente(5)? - Combien d'appels à la fonction
descente()sont réalisés lorsqu'on exécute l'instructiondescente(8)? - Donnez, en fonction de
n, le nombre d'appels à la fonctiondescente()réalisés lorsqu'on exécute l'instructiondescente(n). - En déduire la complexité de cette fonction.
Éléments de réponse
La flèche « → » modélise l'appel suivant.
-
descente(5)→descente(4)→descente(3)→descente(2)→descente(1)→descente(0)(0 n'est pas strictement supérieur à 0, c'est le dernier appel récursif).
Lorsqu'on exécute l'instructiondescente(5), on effectue 6 appels à la fonctiondescente(). -
De la même manière, lorsqu'on exécute l'instruction
descente(8), on effectue 9 appels à la fonctiondescente(). -
Soit
nest négatif ou nul, alors le testn > 0n'est pas validé et il n'y a pas d'appel récursif à la fonctiondescente().
Soitnest strictement positif. Les appels se déroulent alors ainsi :
descente(n)→descente(n-1)→ ... →descente(1)→descente(0).
On effectue doncn+1appels récursifs à la fonctiondescente(). -
Ce nombre d'appels est un multiple de
n: la complexité est linéaire.
Un deuxième exemple☘
On considère la fonction récursive suivante :
1 2 3 4 5 6 7 | |
- Combien d'appels à la fonction
piano()sont réalisés lorsqu'on exécute l'instructionpiano(3)? - Combien d'appels à la fonction
piano()sont réalisés lorsqu'on exécute l'instructionpiano(5)? - Donnez, en fonction de
n, le nombre d'appels à la fonctionpiano()réalisés lorsqu'on exécute l'instructionpiano(n). - En déduire la complexité de cette fonction.
Éléments de réponse
-
piano(3)appelle deux foispiano(2).
Chaque appel de piano(2) appelle deux fois piano(1).
Chaque appel de piano(1) appelle deux fois piano(0).
Chaque appel de piano(0) termine car 0 n'est pas strictement supérieur à 0.
Le nombre total d'appels générés parpiano(3)est donc 1+2+4+8 = 2^4 - 1. -
De la même manière, lorsqu'on exécute l'instruction
piano(5), on effectue 2^6 - 1 appels à la fonctionpiano(). -
Soit
nest négatif ou nul, alors le testn > 0n'est pas validé et il n'y a pas d'appel récursif à la fonctionpiano().
Soitnest strictement positif. On note T(n) le nombre d'appels engendrés par l'exécution depiano(n). Dès lors, T(n) = 2 T(n-1) = 2 \times 2 T(n-2) = \cdots = 2^n \; T(0) appels.
On effectue donc 2^n appelspiano(0). Le nombre total d'appels engendrés parpiano(n)est 1+2^1+2^2+...+2^n = 2^{n+1}-1. -
Ce nombre d'appels est, à une constante près, une puissance n-ième de 2 donc la complexité est exponentielle.