Vous êtes sur la page 1sur 10

Chap02 - Complexité algorithmique

>1 de 10

Chap01 Complexité algorithmique


Gossoni Mohamed
mohamedgossoni@gmail.com
Al khansa - CPGE MP

Plan
I - Introduction:

II - La notion de complexité:

1. Définitions:
2. Notation de Landau: ( ), ( ), ( )
3. Classes de complexité usuelles

III - La complexité algorithmique:

1. Le coût d'instruction:
a- Instructions élémentaires:
b- Instructions composées:
2. Calcul de la complexité algorithmique - Exemples:
3. Différentes nuances de complexité:

I - Introduction:
Un algorithme est une solution à un problème donné, sa fiabilité repose donc sur 3 critères:

La terminaison: Il doit finir, dans tous les cas, par rendre une solution.
La correction: La solution doit être juste.
L'optimalité

En terme de ressource temporelle: Durée d'exécution la plus basse (temps).

En terme de ressource matérielle: Utilisation minimum de la mémoire (espace).

On s'intéresse dans ce chapitre au dernier critère qu'on appellera "la complexité algorithmique" et qui se décompose en
complexité temporelle et complexité spatiale. Le facteur temps est généralement plus important que celui de l'espace. On
focalisera notre étude sur la complexité temporelle.

Exercice:
Soit la suite de Fibonacci définie par la relation récurrente:

1. En se basant sur la relation récurrente, écrire une fonction récursive qui calcule .
2. Ecrire , la version itérative de .
3. En utilisant la bibliothèque et de , comparer graphiquement le temps d'exécution des 2
fonctions, pour dans .
4. Conclure?

Réponses:
1. et 2. les fonctions et :
Chap02 - Complexité algorithmique
1 def fiboRec(n): >2 de 10
2 if n<2:
3 return n
4 return fiboRec(n-1)+fiboRec(n -2)
5
6 def fiboIt(n):
7 if n<2:
8 return n
9 a,b =0,1
10 for i in range(1,n):
11 c=a+b
12 a=b
13 b=c
14 return c
15
3. Test expérimental:

1 import time as tm
2 import matplotlib.pyplot as plt
3
4 x=[i for i in range(10,36)]
5
6 def coutsTemps(f,x):
7 y= []
8 for i in x:
9 t1=tm.time()
10 f(i)
11 t2=tm.time()
12 y.append(t2-t1)
13 return y
14
15 yRec=coutsTemps(fiboRec,x)
16 yIt=coutsTemps(fiboIt,x)
17
1 plt.plot(x,yRec,"-g",label ="Fibo récursive")
2 plt.plot(x,yIt,"-b",label="Fibo itérative")
3 plt.legend(loc="upper left")
4 plt.xlabel("$n$")
5 plt.ylabel("Temps d'exécution")
6
Text(0, 0.5, "Temps d'exécution")

4. Conclusion: l'algorithme de la version récursive roule beaucoup plus lentement dès que dépasse relativement à
celui de la version itérative.

II - La notion de complexité:
1) Définitions:
Définition:
Lacomplexitéd'un problème mathématique est une mesure de la quantité de ressources nécessaires à la
résolution du problème . Cette mesure est basée sur une estimation du nombre d'opérations de base effectuées par
l'algorithme en fonction de de l'algorithme. Pour un même problème , on peut
trouver plusieurs algorithmes ( , , .., ).
L'objectifdelacomplexité
est d'évaluer le coût d'exécution de chaque algorithme afin de choisir le meilleur.
Chap02 - Complexité algorithmique
>3 de 10
Exemple:
Quelle est la taille des données en entrée sur la base de laquelle la complexité de chaque algorithme suivant sera évaluée:

1. Algo1:
Entrée: Liste de floats .
Sortie: Maximum de .

La taille de la liste: .

2. Algo2:
Entrée: Entier .
Sortie: ième terme de la suite de fibonacci.

le nombre de termes calculer jusqu'au .

3. Algo3:
Entrée: Chaîne de caractère .
Sortie: Chaîne de caractère miroir de . Exemple .

La taille de la chaîne: .

4. Algo4:
Entrée: Entier .
Sortie: Nombre de chiffres impairs dans la représentation décimale de .

La taille de dans la représentation décimale.

Définition:
Complexitétemporelle(entemps) est le nombre d'opérations élémentaires (affectations, comparaisons, opérations
arithmétiques) effectuées par un algorithme.
Complexitéspatialeen ( espace)
est le nombre d'emplacements mémoires occupés lors de l'exécution d'un
programme.

Remarque:
On s'intéressera dans ce qui suit, plus, à la complexité temporelle.

2) Notation de Landau: ( ), ( ), ( )
Définitions:
Soit une fonction qui désigne le temps de calcul d'algorithme relativement à , la taille de données mise en jeux.

est en grandode : si et seulement si : telle que , . On


dit que est asymptotiquement majorée par à une constante près.
est en grandoméga de : si et seulement si : telle que ,
. On dit que est asymptotiquement minorée par à une constante près.
est en grandthéta
de : si et seulement si : telle que
, . On dit que et sont asymptotiquement du même ordre de grandeur.

Exemple:
Prouvons que la fonction est en et elle est en , il nous suffira de trouver une constante
qui établit l'inégalité à partir d'un rang :

Pour on vérifie par exemple que: , dés que .


Pour on vérifie par exemple que: , dés que
Pour où on vérifie par exemple que: , dés que
Chap02 - Complexité algorithmique
>4 de 10
Remarques
On définit ainsi des classes de complexité, c'est pourquoi on note aussi: , et .
On a:
pour .
pour .
La classe de complexité de est la plus petite classe telle que
On peut faire les simplifications suivantes:

On ignore les constantes multiplicatives (elles valent 1): , +
.
On annule les constantes additives , .
On ne retient que les termes dominants .

Propriétés
Temps constant: on a toujours . (P1)
La réflexivité: on a toujours . (P2)
La transitivité: Si et alors . (P3)
La somme:
Si et , alors . (P4)
Si et , alors . (P5)
Le produit: Si et , alors . (P6)

3) Classes de complexité usuelles


Complexité Nomcourant Description

Constante Le temps d'exécution ne dépend pas des données traitées, ce qui est assez rare !

Logarithmique Augmentation très faible du temps d'exécution quand le paramètre croit.

Linéaire Augmentation linéaire du temps d'exécution quand le paramètre croit (si le paramètre double, le temps double).

Quasi-linéaire Augmentation un peu supérieure à .

Quand le paramètre double, le temps d'exécution est multiplié par . Exemple : algorithmes avec deux boucles
Quadratique
imbriquées.

Ici, est le terme de plus haut degré d'un polynôme en ; il n'est pas rare de voir des complexités en
) Polynômiale
ou .

Exponentielle Quand le paramètre double, le temps d'exécution est élevé à la puissance avec .

Factorielle Asymptotiquement équivalente à .


Chap02 - Complexité algorithmique
>5 de 10

III - La complexité algorithmique:


1) Le coût d'instruction:
a- Instructions élémentaires:

Définition:
On appelle instruction de base, ou instruction élémentaire, toute :

1. Affectation.
2. Test de comparaison : , , , , .
3. Opération de lecture ( ) et écriture ( ).
4. Opération arithmétique : , , , , , .

Le coût d'une opération élémentaire est constant donc il est en .

Exemple:
Que vaut le coût de l’algorithme :

1 somme = n + 1 #instr1
2 somme = somme ∗ n #instr2
3 somme = somme/2 #instr3
4

b- Instructions composées:
Définition:
On appelle instruction composée toute instruction contenant:

1. Une structure conditionnelle:

1 if test: A else B
2

Et on a:

2. Une structure de boucle :

1 for i in range(p,n): Ai
2

Et on a:

3. Une structure de boucle :

1 while t: At
2

Et on a:

4. Autres instructions composées et élémentaires: Le coût est la somme des coûts de ses éléments.
Chap02 - Complexité algorithmique
>6 de 10

2) Calcul de la complexité algorithmique - Exemples:


On calculera dans ce qui suit la complexité maximale (dans le sens de la majoration):

Exemple1
La fonction suivante permet de retourner le quotient et le reste de la division entière d'un nombre entier par (non nul).

1 def division(a,b) :
2 q=a//b
3 r=a%b
4 return (q,r)
5

Le nombre d’opérations est quelque soient et . Le nombre d'opérations est constant et le temps de calcul l'est aussi.

La complexité est donc .

Exemple2
La fonction suivante retourne la somme des éléments d'une liste :

1 def somme(L) :
2 s=0
3 n=len(L)
4 for i in range (n) :
5 s=s+L[i]
6 return s
7

Le paramètre de complexité est la taille de la liste d'entrée . On exécute dans le corps de la boucle 3 opérations
(addition, affectation et accés à ) pour itérations. Le nombre total d'opérations est : .

Complexité :

Exemple3:
La fonction suivante permet de remplir une matrice par l'utilisateur:

1 def RemplirMatrice(M) :
2 n=len(M)
3 p=len(M[0])
4 for i in range(n) :
5 for j in range(p) :
6 print("T[",i,"][",j,"]=")
7 T[i][j]=int(input())
8

Le paramètre de complexité est la taille de la matrice d'entrée et le coût pour saisir une valeur est (print, input,
int et affectation). Les deux boucles imbriquées multiplie ce coût par (nombre d'itérations total). Le nombre total
d’opérations est :

Complexité : , si

Exemple4:
La fonction suivante retourne la matrice produit de 2 matrices et sur la base de la formule:

:
Chap02 - Complexité algorithmique
>7 de 10
1 def ProduitMatriciel(A,B) :
2 n=len(A) #nombre de lignes de A
3 m=len(A[0]) #nombre de colonne de A
4 p=len(B[0]) #nombre de colonnes de B
5 C=[p*[0] for i in range(n)]
6 for i in range(0,n) :
7 for j in range (0,p) :
8 s=0
9 for k in range (0,m) :
10 s = s + A[i][k]*B[k][j]
11 C[i][j]=s
12 return C
13

Les paramètres de complexité sont les tailles et des matrices d'entrée et


Et le coût pour calculer une valeur de est (produit, addition et affectation) qui sera multiplié:

par de la boucle " "


puis par de la boucle " "
puis par de la boucle " ". Le nombre total d’opérations est: et si les matrices sont carrées
:

Complexité : , si .

Exemple5:
La fonction suivante effectue une recherche dichotomique de dans un tableau trié de taille :

1 def RechDichotomique(T,x) :
2 g,d=0,len(T)- 1
3 while g<=d :
4 m=(g+d)//2
5 if T[m]==x :
6 return True
7 if T[m]<x :
8 g=m+1
9 else :
10 d=m-1
11 return False
12

Le paramètre de complexité est la taille . Les coût à l'exterieur de la boucle et à son interieur sont constants,
donc le coût total est majoré par où est le nombre de passages maximum dans la boucle .
Ce nombre dépend de la taille de la liste en cours de traitement dans la boucle.
Pour majorer le coût on considère que c.a.d n'est plus vérifiée.

Avant le 1èr passage: La liste à traiter est de taille .


Avant le 2ième passage: La sous liste à traiter est de taille maximale car:
Si :
.
Si :
.

Et par récurrence on montre que:

Avant le ième passage: La sous liste à traiter est de taille maximale .


Chap02 - Complexité algorithmique
>8 de 10

Avant le ième maximum dérnier passage possible ( ), on traite la sous liste de taille atteint au
maximum si .
Donc vérifie: soit: ou encore:
Soit .

Complexité : .

Exemple6:
La fonction suivante effectue une recherche d'un de taille dans un de taille et retourne sa position s'il est
trouvé ou sinon:

1 def searchWord(mot,texte) :
2 m,n=len(mot),len(texte)
3 if m>n:
4 return False
5 for i in range(n-m+1) :
6 j=0
7 while j < m and mot[j] == texte[i + j] :
8 j=j+1
9 if j == len(mot) :
10 return i
11 return False
12

Le nombre d'opérations total est de l'ordre de . En particulier le maximum est atteint pour
Car: pour fixe la fonction trinôme est maximale à
et on obtient le coût maximal: .

La complexité de l'algorithme est

Exemple7:
La fonction suivante résout récursivement le problème des "Tours de Hanoï":

Déplacer, un par un, les disques de la tour vers la tour en utilisant la tour et en respectant l'ordre
du plus grand au plus petit (du bas vers le haut) dans chaque tour.

1 def hanoi(n,a=1,b=2,c=3) :
2 if (n > 0) :
3 hanoi(n-1,a,c,b)
4 print("Déplace ",a,"sur",c)
5 hanoi(n-1,b,a,c)
6
Chap02 - Complexité algorithmique
>9 de 10
L'opération élémentaire étant le mouvement d'un plateau, pour déplacer une tour de taille , il faut déplacer deux
tours de taille et un plateau (déplacer une tour vide, c'est ne rien faire). La complexité vérifie donc

ou encore, avec

Donc

Donc la complexité est exponentielle .

3) Différentes nuances de complexité:


Pour des données de même taille, un algorithme n'effectue pas nécessairement le même nombre d'opérations élémentaires.
Pour cela, on distingue 3 types de complexité :

1. Complexité au pire des cas.


2. Complexité dans le meilleur des cas.
3. Complexité en moyenne des cas.

Définition
Soit l’ensemble des données de taille fixe d'un algorithme et est le coût de son exécution sur de .

La complexité au pire des cas de l'algorithme, est le plus grand nombre d'opérations qu'il aura à exécuter sur :
, .
La complexité au meilleur de l'algorithme, est le plus petit nombre d'opérations qu'il aura à exécuter .
, .
La complexité en moyenne de l'algorithme, est la moyenne des ses complexités sur :
où est la probabilité d'avoir la donnée en entrée de l'algorithme.

Remarque
Les complexités calculées aux exemples précédents sont aux pires des cas.

Exemple
Ecrivons l'algorithme de la recherche d'un élément dans un tableau de taille et calculons la complexité dans:

Le pire et meilleur cas.


Le cas moyen étant données:
Les événements =" est dans la liste" et =" est à la position ".
Les probabilités: et .

1 def find (T,x) :


2 n=len(T)
3 for i in range(n):
4 if T[i] == x :
5 return True
6 return False
7

Le pire des cas: L'élément recherché est le dernier (dans la case ) ou il est absent.

Donc la complexité dans le pire est .

Le meilleur des cas: L’élément recherché se trouve en 1ére position.

Donc la complexité dans le meilleur des cas est .


Chap02 - Complexité algorithmique
>10 de 10
En moyen des cas: Pour calculer la complexité moyenne on considère les événements: " se trouve dans le
tableau" et " est à l'indice ", avec les hypothèses: et (équiprobabilité).

D'où le jeu de données avec " est à la position au tableau" et


" ne se trouve pas au tableau", donc: et .

Donc la complexité en moyenne des cas:

Exercice:
Calculer la comlexité des fonctions et écrites au 1er exercice.

1 def fiboRec(n):
2 if n<2:
3 return n
4 return fiboRec(n-1)+fiboRec(n-2)
5
6 def fiboIt(n):
7 if n<2:
8 return n
9 a,b=0,1
10 for i in range(1,n):
11 c=a+b
12 a=b
13 b=c
14 return c
15

Réponses:
Soit est le coût cherché.

1. : Il est évident que et en (une complexité linéaire).

2. : vérifie

En posant on obtient la suite récurrente linéaire , d'équation caractéristique:

Cette dernière à pour solution et


Donc le terme général de la suite est . verifiant les conditions
Et comme car , alors est en et aussi (une complexité exponentielle).

Vous aimerez peut-être aussi