Vous êtes sur la page 1sur 61

Chapitre 2

Récursivité
&
Complexité
Algorithmique

1
Plan

 Récursivité
 Récursivité des actions
 Récursivité des objets
 Complexité
 Complexité spatiale
 Complexité temporelle

2
Récursivité des actions

 La récursivité des actions se définit par


des fonctions et procédures
récursives: un sous-programme récursif
contiendra au moins un énoncé d’appel à
lui même dans son corps.

 Le nombre d’appels récursifs est infini


d’où la nécessité d’introduire
TOUJOURS l’appel récursif dans un
énoncé conditionnel pour assurer l’arrêt
du programme

3
Récursivité des actions

 Finitude du sous-programme P à prouver


(=BASE):
 Un ou plusieurs paramètres sont
associés à P, ils décrivent son
domaine d’application
 Les valeurs de ces paramètres
DOIVENT évoluer pour restreindre le
domaine d’application et tendre vers
une valeur particulière qui arrêtera les
appels récursifs
 Plusieurs type de récursivité des
actions
 Récursivité terminale
 Récursivité non terminale
 Récursivité croisée
 …
4
Récursivité non
terminale
 Un appel récursif est dit non terminal
s’il est suivi d’un traitement

Procédure PRECNT(U)
var L;
Début
Si C alors
D;
PRECNT (f(U));
E;
sinon
T;
Finsi
Fin
5
Exemple

static int factRecNT(int n)


{int r;
C if (n>1)
{r= factRecNT(n-1);
E r=r*n; }
else
T {r=1;}
return r;}

 Rq: factRecNT n'est pas terminale, puisqu'il y a


multiplication par n avant de retourner.
 Travail à faire Exécution avec n=4

6
Solution
factRecNT(4)
r=24

r=factRecNT(3)
r=6*4

r=factRecNT(2)
r=2*3

r=factRecNT(1)
r=1*2

r=1

7
Récursivité terminale

 Un appel récursif est dit terminal s’il


n’est suivi d’aucune instruction

Procédure PRECT(U)
var L;
Début
Si C alors
D;
PRECT(f(U));
Sinon
T;
Finsi
Fin

8
Exemple

Calcul du factoriel (version terminale):

static int factRecT(int n, int r)


C { if (n>1) {
return factRecT(n-1,n*r); }
T else { return r; } }

 Rq: initialement r=1


 Travail à faire: Exécution avec n=4

9
Définition d’un module
récursif

 Pour définir un module


récursif :
 Paramétrage du problème
 Recherche d’un cas particulier
permettant d’arrêter le
processus d’appel récursif
 Décomposition du cas général

10
Exemple : Tours de
Hanoi
 N disques sont empilés par ordre de
diamètre décroissant (tous les disques
sont de diamètres différents) sur un
piquet A. deux autres piquets B et C
peuvent recevoir des disques, à condition
que ceux-ci soient toujours empilés selon
la même règle du diamètre décroissant.
 Le but est de transporter les N disques du
piquet A au piquet C, en utilisant
éventuellement le piquet B, tout en
respectant les deux règles suivantes :
 ne déplacer qu’un seul disque à la fois

 ne placer un disque que sur un disque


de diamètre supérieur, ou un piquet
libre

11
Démarche récursive
 Paramétrage du problème :
 N : nombre de disques
 A, B, C : les piquets (départ, intermédiaire et
arrivé)
 Recherche de la valeur d’arrêt :
 Si (N = 1) Alors Déplacer un disque de A vers
C :Déplacer (A, C)
 Décomposition du cas général :
 Résoudre le problème pour N disques ne
présente pas de difficulté si on sait le résoudre
pour N-1 disques
 Transporter les N disques du piquet A au
piquet C :
 Transporter les N-1 premiers disques de A

vers B (C piquet intermédiaire)


 Déplacer le disque restant de A vers C, et

enfin
 Transporter les N-1 disques de B vers C (A

piquet intermédiaire).

12
Illustration
A B C

13
Algorithme

14
Travail à faire
 Hanoi avec n= 4
 3 de B via C
 A vers B
 A vers C
 B vers C
 A vers B 7 déplacements
 C vers A
 C vers B
 A vers B
 1 de A vers C (1 déplacement)
 3 de B vers C via A
 B vers C
 B vers A
 C vers A
 B vers C 7 déplacements
 A vers B
 A vers C
 B vers C 15
Récursivité des objets
(1)
 Un objet récursif est un objet qui contient un ou
plusieurs composants du même type que lui
 Exemple : le type Arbre Généalogique

Class ArbreGénéalogique {
String prénom;
ArbreGénéalogique mère, père; //définition de
l’ascendance
ArbreGénéalogique(String s)
{
prénom = s;
}}

 les attributs mère et père sont des références à


des objets de type ArbreGénéalogique et non pas
l’objet lui-même

 Les instances doivent être créer et lier entre elles


explicitement

16
Récursivité des objets
(2)
 Les objets récursifs ont une nature
dynamique : leur taille peut varier
au cours de l’exécution du
programme
 Certains langage (C, Pascal ..) ne
permette pas une définition
directement récursive d’objets
mais l’autorisent au moyen des
pointeurs
 Java permet des définitions
d’objets vraiment récursifs

17
Check point

1. Types de récursivité ?
2. Natures de récursivité ?
3. Si on a un programme
récursif non terminal
quelle est l’idée pour le
transformer en récursif
terminal

18
Complexité Algorithmique

19
Complexité algorithmique

 Critères d’évaluation d’un


programme
 Est-ce que le programme satisfait
les spécifications de la tâche ?
 Est-ce qu’il fonctionne
correctement ?
 Est-il bien documenté ?
(commentaires, guide d’utilisation)
 Est-ce que le code est lisible ?
 …

 Ces critères sont associés


au développement

20
Complexité algorithmique

 Évaluation de performances d’un


programme
 Est-ce que le programme utilise

efficacement la mémoire ?
 Est-ce que son temps d’exécution est
acceptable?
Complexité des algorithmes
 Estimations de temps et d’espace
 Indépendants de la machine

21
Complexité spatiale

 La complexité spatiale d’un algorithme est la


quantité de mémoire nécessaire à son
exécution complète.
 Soit Espace(P) l’espace mémoire exigé

par un programme P
 Espace(P)=

besoins en espace mémoire fixe


(instructions + variables +constantes)
+ besoin en espace mémoire variables
(en général à l’exécution)

22
Complexité temporelle

 La complexité temporelle d’un algorithme est


la quantité de temps nécessaire à son
exécution complète

 Le temps d’exécution est proportionnel au


nombre d’opérations fondamentales
effectuées par l’algorithme

 Opérations fondamentales : addition,


soustraction, comparaison, multiplication, …

 On supposera que chaque opération


fondamentale de l’algorithme prend un
temps unitaire (1)

23
Types de mesure de
complexités

 complexité dans le meilleur des cas


 complexité dans le pire des cas
 complexité en moyenne

24
Complexité temporelle
 Il n'existe pas de mode d'emploi qui donne à
chaque fois l'estimation de la performance d'un
algorithme.

 Mais on peut toujours se baser sur la fait que


les algorithmes sont conçus de manière
structurée.

 Les algorithmes structurés combinent les


instructions de contrôles de 4 manières
différentes:
 Séquence d'instruction

 Schéma décisionnel

 Boucle ou itération

 Appel à un sous programme

 P(I) note le nombre d’opérations


fondamentales effectuées par l’instruction I
(séquence d’instructions, schéma décisionnel,
etc.) 25
Instruction simple

 Pour les instructions simples qui ne font


pas appel à un sous programme comme
l'affectation et les opérations de
lecture/écriture l'instruction prend un
temps d'exécution fixe (constant) dénoté
O(1) : de l’ordre de 1

 Une séquence d'instructions simples prend


la somme des temps d'exécution de
chaque instruction dans la séquence.

 Si chaque instruction est en O(1) alors la


somme l'est aussi.

26
Schémas de choix

 Pour les schémas de choix ou schémas


décisionnels, on retiendra la complexité
maximale des différentes alternatives.

P(if(cond) I1 else I2) ≤


P(cond)+max(P(I1), P(I2))

27
Schémas itératifs (1)
 Hypothèse: le traitement à l’intérieur de la
boucle est O(1)
 Si le nombre d’itérations est constant alors la
complexité est O(1)
 Exemple: Parcours d'un intervalle constant
1..5 alors la complexité est O(1)

 Sinon si le nombre d’itérations est fixée à N


alors la complexité est O(N)

 Exemple:
Pour i = 1..N Faire
opérations en O(1) N opérations
FinFaire

28
Schémas itératifs (2)
 2 boucles imbriquées (chacune à N itérations) avec
des instructions en O(1) : Complexité = O(N2)
 3 boucles imbriquées (chacune à N itérations) avec
des instructions en O(1) : Complexité = O(N3)
 …
 M boucles imbriquées (chacune à N itérations) avec
des instructions en O(1) : Complexité = O(NM)
 Exemple:

Pour i = 1..N Faire


Pour j=1..N faire
opérations en O(1)
FinFaire

FinFaire

N opérations qui vont se faire N fois donc N*N=N2

29
Boucles multiplicatives (1)

 Les boucles multiplicatives sont des


boucles contrôlées par une variable qui, à
chaque exécution de la boucle, est divisée
ou multipliée par une constante.
 Exemple:

var  1
Tantque var <= N faire
…….
qqchose en O(1)
…….
var  2*var
FinFaire

Ici, la constante = 2 30
Boucles multiplicatives (2)
 Puisque var est initialisé à 1, après k itérations la variable var
sera égale à 2k (car à la sortie de la 1ère itération var=2=21
puis à la sortie de la 2ème itération var=4=22, à la sortie de la
1ere itération var=8=23 etc.)
 Pour trouver la complexité temporelle il faut trouver k
 Le nombre d'itérations k peut être trouvé en appliquant la
fonction logarithme des deux côtés de l'égalité
var = 2k
log2(var) = log2 (2k) N
= k log2(2)
=k
Donc k = log2(var)

 Puisque l'itération se termine quand var >= N, la complexité


de l'algorithme est en O(log2(N))

31
Boucles multiplicatives (3)

 En général, si l'on suppose que la variable


de contrôle var est multipliée par une
constante Facteur, alors on peut voir
qu'après k itérations, var = Facteurk
 Dans ce cas :

var = Facteurk
logFacteur(var) = logFacteur (Facteurk)
= k logFacteur (Facteur)
=k
Donc k = logFacteur (var)

Pour var = N, k= logFacteur (N)

32
Travail à faire

 Donner la complexité de l’algorithme


suivant

var  N
Tantque var ≠ 0 Faire
……..
qqchose en O(1)
……..
var  var/2
FinFaire

33
Travail à faire (sol)
 Puisque var est initialisé à N, après k itérations la
variable var sera égale à N/2K
 Le nombre K peut être calculé comme suit:
var = N/2K
log2(var) = log2 (N/2K)
= log2(N)-log2(2K)
= log2(N)-K*log2(2)
= log2(N)-K

Donc k = log2(N) - log2(var)

 Puisque l'itération se termine quand var= 0 on va


considérer la limite de la fonction logarithmique qui est
une constante (puisque log 0 est une forme
indéterminée qui tend vers l’infini)
 la complexité de l'algorithme est en O(log2(N))
34
Récap
 Cela revient au même que d'initialiser la variable var
de parcours à une grande valeur et de la diviser par
une constante (ici 2) pour la faire converger vers une
petite valeur que d'initialiser la variable var de
parcours à une petite valeur et de la multiplier par une
constante (ici 2) pour la faire converger vers une
grande valeur.

Compteur
avec un Compteur
pas de 1 avec un
pas de 2

 En général la complexité algorithmique est en


O(logBase du multiplicateur ou du diviseur (N)) 35
Complexité en
O(N log(N)) (1)
Boucles imbriquées
 Exemple 1:

Pour i = 1..N Faire


var  1
Tantque var <= N Faire
……
qqchose en O(1)
……
var  Const*Var
FinFaire
FinFaire

Complexité en O(N logConst(N))

36
Complexité en
O(N log(N)) (2)
Boucles imbriquées
 Exemple 2:

Pour i = 1..N Faire


var  N
Tantque var ≠ N Faire
……
qqchose en O(1)
……
var  Var/Const
FinFaire
FinFaire

Complexité en O(N logConst(N))

37
Règles
 c f(n) = O(f(n)) pour tout facteur
constant c
 f(n) + c = O(f(n)) pour tout facteur
constant c
 f(n) + g(n) = O(max(f(n), g(n)))
 f(n) x g(n) = O(f(n) x g(n))
 Si f(n) est un polynôme de degré m:
f(n)=a0+a1n+a2n2+…+amnm
alors f(n) est de l’ordre du degré le plus
grand : O(nm)
 nm = O(cm) pour tout m  0 et c  1
 log nm = O(log n) pour tout m  0
 Log n = O(n)

38
Exemple 1 (1)
 Pour les fonctions de tris la mesure de complexité
correspond au nombre de comparaisons d’élément
exprimé en fonction du nombre d’élément à trier
 Exemple:

Algo Tri par sélection


-- Précond: tab contient n valeurs, n > 1
-- Postcond: trie par sélection en ordre croissant des n
valeurs de tab
pourtout i de 1 à n-1 faire
min  i
pourtout j de i+1 à n faire
si tab[j] < tab[min] alors min  j finsi
finpour
échanger tab[i] et tab[min]
finpour

39
Rappel
• la somme des n premiers termes d’une suite
géométrique de premier terme u0 et de raison q 1
est:
n
1 qn 1  raison nbre de termes


k 0
u k  u 0
1 q
 1er
terme 
1  raison
• la somme des n premiers termes d’une suite
arithmétique de premier terme u0 et de raison r est:
n
(n  1)(u0  un )
 uk 
k 0 2
nbre termes de la somme (1er terme  d er termes )

2

• le nième terme d’une suite arithmétique de premier


terme u0 et de raison r est:

un  u0  n * r
40
Exemple 1 (2) - Solution
 La complexité spatiale = O(n):
 si on multiple par 100 le nombre d’éléments à trier
le programme utilise un tableau 100 fois plus grand
 La complexité temporelle = O(n2):
 À chaque étape i du tri la comparaison est exécutée
par la boucle la plus interne n-i fois.
 Il y a n-1 étapes (dans la boucle externe)
 Étape 1: n-1 comparaisons

 Etape 2: n-2 comparaisons

 …

 Etape n-1: 1 comparaison

 C’est une suite arithmétique dont le premier terme


est 1, le dernier (n-1) et la raison est de 1. Donc le
nombre de comparaisons exécuté est :

n 1
(n - 1) (1  n  1) n  n 2


k 1
uk 
2

2
41
Exemple 1 (3) - Solution

 La fonction (n2-n)/2 est un polynôme de


degré 2 donc la complexité temporelle est
de l’ordre de O(n2)

 Cela signifie que si on multiplie par 100 le


nombre d’éléments à trier alors le temps
d’exécution sera multiplié par 10000

42
Signification
Pourquoi ½(n2-n) est approximé par 0(n2 ) ?
 Soit deux fonctions positives f et g, on dit que
f(n) est en O(g(n)) (de l’ordre de g(n)) s’il
existe deux constantes positives c et n0 t.q  n 
n0, f(n)  c g(n)
 Dans notre exemple : f(n)= ½(n2-n) et g(n)=
n2 car pour c=1/2 et n0 = 0 on a  n  0,
½(n2-n) ≤ ½ n2

½ n2
40

35

30
½ (n2-n)
25

20

15

10

0
0 43
Exemple 2 (1)

 factorielle d’un entier n

 version itérative

static int factIter(int n)


{ int r=1;
for(int i=1; i<=n; i++) r=r*i;
}

 version récursive (Non Terminale)

static int factRec(int n)


{
if(n==0) return 1;
else return n*fact(n-1);
}

 Rq: Opération fondamentale : multiplication

44
Exemple (2) - Solution

 Mesure de la complexité temporelle

 Version itérative
P(i) =1, il ya n itérations   P(i) = n
complexité O(n)

 Version récursive
P(0)=0, P(n)=P(n-1)+1=n
complexité O(n)

 Mesure de la complexité spaciale


 Version itérative  complexité O(1)

 Version récursive  complexité O(n)

45
Résumé

1 constante (indépendante de la
taille des données)
log2 n logarithmique
n*log (n) quasi-linéaire

n linéaire

n2 quadratique

n3 cubique

nP polynomiale

cn (c  1) exponentielle

46
Illustration (1)

 Temps d’exécution : Exemple


 Sur un ordinateur effectuant 1000 000 opérations
par seconde (1 Mhz)
 s : micro-secondes, ms : milli-secondes,

s :secondes, mn:minutes, h : heure, j : jour,


a : année,
Complexité
Taille
log(n) n n*log(n) n2
n=102 6.6s 0.1ms 0.6 ms 10 ms
n=103 9.9s 1 ms 9.9 ms 1s

n=104 13.3s 10 ms 0.1 s 100 s

n=105 16.6s 0.1 s 1.6 s 2.7 h


n=106 19.9s 1s 19.9s 11.5 j

47
Illustration (2)

Complexité
Taille
n3 2n
n=102 1s 4x106 a
n=103 16.6 mn >10100 a

n=104 11.5 j >10100 a

n=105 31.7 a >10100 a


n=106 31.7x103 a >10100 a

48
Illustration (3)

complexité

9000
8000
7000
n2
n2
6000 n3
n3
temps

5000 2n
4000
2n
3000
2000
1000
0
8 9 10 11 12 13
taille des données

49
Illustration (4)
Ici on change l’échelle car
elle varie beaucoup avec les
vals précédentes le point
d’attache entre les deux
graphique c'est n2
complexité

137,63

log n
103,22
n
temps

n log n
68,81 n2
n2

34,41

0,00
1

11

13

taille des données

50
Conclusion

Un bon compromis
espace-temps

51
Travail à faire (1)

 1. Calculer la complexité temporelle de la fonction de


recherche d’un élément dans un tableau

fonction, Appartient (donnée T : tableau d’entiers, donnée N,


x : entier) retourne booléen

début
variable i : entier
i  1;
tantque ( i ≤ N et T[i] ≠ x) faire
i i+1
fin tantque
si (i>N) retourner faux
sinon retourner vrai
finsi
fin

 Opérations significatives : comparaisons

 2. Calculer la complexité temporelle et la complexité spatiale


des tours de Hanoi ?

52
Travail à faire (2)
 3. Complexité temporelle de la recherche
dichotomique
 Recherche d’un élément dans un tableau de n
éléments triés
 Principe: diviser l’intervalle en 2 et tester sur
l’élément du milieu si ok arrêt sinon recherche à
droite ou à gauche

53
Solution du travail
à faire

54
Travail à faire –
Recherche (Sol)
 invariants de boucle : propriétés vraies à chaque
itération
 1ère itération : i=1
 kième itération : i=k, et  j [1,k[, T[i] ≠x
(preuve par récurrence sur k)
 conditions d’arrêt :

 si à la kième itération : k ≤ N et T[k]=x  arrêt


avec i=k
 si k>N  arrêt avec i=n+1 (élément non trouvé)
(preuve par récurrence sur k)

 Complexité :
 Il y a au plus N itérations (N est la taille des
données)
 La complexité est de N au pire des cas: O(N)

55
Travail à faire
Tours de Hanoi (sol) (1)

 Complexité temporelle:
Soit Un le nombre de déplacements
pour n disques. Dans ce cas on
effectue:
Un-1 déplacements
+
1 déplacement
+
Un-1 déplacements
============
Un = 2(UN-1) + 1 déplacements

56
Travail à faire
Tours de Hanoi (sol) (2)
Un = 2 Un-1 + 1
On multiplie par 2 pour
2 (Un-1)= 2 (2 Un-2 + 1) eliminer 2 Un-1

4(Un-2)= 4 (2 Un-3 + 1)

23(Un-3)= 23 (2 Un-4 + 1)

2n-3 (U3) = 2n-3 ( 2 U2 + 1)

2n-2 ( U2)= 2n-2 ( 2 U1 + 1)

Somme Un = 2n-1 U1 + 1 + 2 + 22 + ….+2n-3 +2n-2


n2

 i C’est la somme d’une suite


= 2n-1 + 2 géométrique de raison 2
i 0 Or la somme des n premiers
= 2n-1+ 2n-1 –1 termes d’une suite géométrique
de premier terme u0 et de raison
= 2 (2n-1)-1
= 2n-1+1 -1
q est:
1 q n
u0
= 2n -1 =O(2n) 1 q
On a n-1 termes , donc
Pour n disques on a 2n -1
n 1
n2
1  2 déplacements Donc la complexité

i 0
2 i
 1
1 2
 2 n 1
1 temporelle est de O(2n)
57
Travail à faire
Tours de Hanoi (sol) (4)

 Complexité spatiale:

la complexité spéciale est de O(n)


Car lorsque l’appel récursif est effectué sur une
branche il réserve n fois le nombre de variables
(qui sont de 4) cad 4*n donc O(n) mais cette
réservation est effectuée branche par branche

58
Travail à faire
Recherche dichotomique
(Sol) (1)

Fonction RechercheDicho(Tab: tableau Entier, N : Entier, elem :


Entier): Entier
Début, Milieu, Fin : Entier
Début
Début  1 O(1)
Fin  N O(1)
Milieu  (Début + Fin) Div 2 O(1)
Tantque Début<=Fin et Tab[Milieu] ≠ elem Faire O(1)
Si Tab[milieu] < elem
Alors Début  Milieu +1
Sinon Fin  Milieu – 1
O(1)
FinSi
Milieu  (Début + Fin) Div 2 O(1)
FinFaire
Si Début > Fin
Alors RechercheDicho  -1
Sinon RecherDicho  Milieu O(1)
FinSi
Fin Boucle multiplicative O(Log2(N))
(Voir détails)

Complexité finale:
O(1)+O(1)+O(1)+O(1)+O(Log2(N))+O(1)=O(Log2(N))
59
Travail à faire
Recherche dichotomique
(Sol) (2)

 Supposons que N=2p (cad c’est un nombre qui s’écrit en


puissance 2) alors

Numéro du test Nombre d’éléments dans l’intervalle


1er N
2 N/2
3 N/22
… …
p N/2p-1
p+1 N/2p arrêt car il reste un élément puisque
N=2p donc N/2p = 2p / 2p =1

 Donc le nombre maximum de test (pire) est p+1


 Or log2 (2p) = log2 (N)
 p* log2 (2) = log2 (N)
 p* 1 = log2 (N)
 p = log2 (N)
 p +1= log2 (N) + 1
 Cad au pire on a log2 (N) + 1 tests
 La complexité au pire est O(log2 (N)) 60
Travail à faire
Recherche dichotomique
(Sol) (3)
 Plus généralement (on prend en considération le cas où i N ne
s’écrit pas sous forme de 2p) on considère le plus grand p tel
que: 2p  N > 2p-1 (exemple pour 15, p=4)

Numéro du test Nombre d’éléments dans l’intervalle


1er N
2 N/2
3 N/22
… …
p N/2p-1
p+1 N/2p arrêt car il n ya plus d’ éléments à tester
(le nombre restant est  0,.. (sensiblement
proche de 1) puisque 2p  N )

 Donc le nombre maximum de test (pire) est p+1


 Or log2 (2p)  log2 (N) > log2 ( 2p-1 )
 p* log2 (2)  log2 (N) > (p-1)* log2 (2)
 p* 1  log2 (N) > p-1
 p  log2 (N) > p-1
 p +1  log2 (N) + 1 > p
 Cad au pire on a un nombre de tests qui approche log2 (N) + 1 tests
 La complexité au pire est O(log2 (N))
61