Académique Documents
Professionnel Documents
Culture Documents
Complexité algorithmique
1. Introduction
L’algorithmique est l’étude des algorithmes. Un algorithme est une suite d’instructions qui décrit
comment résoudre un problème donnée en un temps fini.
2. Activité :
Vérifier si un tableau L est trié en ordre strictement croissant.
Raisonnement :
-Un tableau L est trié si tous ses éléments respectent l’ordre croissant. C’est-à-dire Ɐ i [1, taille du
tableau], L[i]<L[i+1]
-On peut aussi traiter ce problème par vérifier s’il y a un contre-exemple. C’est-à-dire s’il i[1,
taille du tableau], L[i]>L[i+1]
on demande d’écrire une fonction Verification qui permet de vérifier cette propriété.
Fonction verification(L[10],n :entier) :booléen
Début
i1
Tantque (i<n) et (L[i]<L[i+1]) faire
ii+1
fin faire
retourner (i>=n)
fin
La question la plus fréquente que se pose à chaque programmeur est la suivante :
Comment choisir parmi les différentes approches pour résoudre un problème ?
La solution algorithmique doit :
- résoudre correctement et de manière efficace le problème.
- être efficace. L’efficacité est évaluée par :
- assure la rapidité : la solution doit avoir un temps d’exécution acceptable (non lente
- prendre en compte la consommation des ressources (espace mémoire utilisée, espace de
stockage)
NB :
-un programmeur doit savoir résoudre un problème et en plus le résoudre efficacement
-l’efficacité des algorithmes est étudiée par la théorie de la complexité.
Dans ce cours on s’intéresse à l’efficacité en terme de temps d’exécution.
3. Définition
La complexité est une branche de l’informatique théorique. Un algorithme à partir d’une donnée
établit un résultat. La taille de la donnée est mesurée par un entier n.
La théorie de la complexité permet de :
- classer les problèmes selon leur difficulté et efficacité
- comparer les algorithmes résolvant un problème donné afin de faire un choix sans devoir les
implémenter
Un algorithme est dit « optimal » s’il possède une complexité minimale parmi les algorithmes de sa
classe.
4. Evaluation de temps d’exécution d’un algorithme
4.1 l’unité de temps
La durée d’exécution d’un algorithme n’est pas mesurée en heure, minutes et secondes. Ces
mesures ne sont pas pertinentes car le même algorithme sera plus rapide sur une machine plus
puissante.
Pour mesuré l’efficacité d’un algorithme on utilise des unités de temps abstraites et
proportionnelles au nombre d’opérations effectuées.
4.2 Les règles de calcul du temps d’exécution
1
- chaque instruction basique consomme une unité de temps telles que les instructions d’affectation,
de lecture, d’écriture, de comparaison…
- Chaque itération d’une boucle rajoute le nombre d’unités de temps consommées dans cette
boucle.
- Chaque appel de fonction rajoute le nombre d’unités de temps consommées dans cette fonction
- Pour compter le nombre d’opérations effectuées par l’algorithme, on additionne le tout
4.3 Exemples
a) Calculer le temps d’exécution de l’algorithme suivant :
Algorithme addition
Variable
X, y, S : entier
Début
Ecrire (″donner la valeur de x″) 1 écriture
Lire (x) 1 lecture
Ecrire (″donner la valeur de y″) 1 écriture
Lire (y) 1 lecture
sx+y 1 addition et 1 affectation (2 opérations)
ecrire (″la somme est : ″, S) 1 écriture
Fin
Donc, au total cet algorithme consomme 1+1+1+1+2+1=7 opération
b) Donner le temps d’exécution de la fonction suivante :
Fonction factorielle (n :entier) :entier
Variable
Début
p1 1 affectation
i2 1 affectation
Tant que (i<=n) faire 1 comparaison il s’agit d’une boucle qui
pp*i 1mul et 1 affectation doit être exécutée (n-1)
ii+1 fois
fin faire 1 addition et 1 affect
retourner (p)
fin 1 retour du résultat
Sachant que : n !=n*(n-1)*(n-2) …*2*1 avec 0 !=1
La boucle commence à partir de la valeur 2 puisque pour 0 !=1 et 1 !=1
Donc, au total le temps d’exécution de cet algorithme est :
1aff+1aff+ (1comp+1mul+1aff+1add+1aff)*(n-1)+1=5(n-1)+3=5n-2 operations
c) Calculer la complexité algorithmique en terme de temps d’exécution de la fonction
suivante :
Fonction
Verification(L[10],n :entier) :booléen
Début 1 affectation
i1 2 comparaisons le traitement est
Tantque (i<n) et (L[i]<L[i+1]) faire réalisé
ii+1 1 affectation et 1 addition (2) au pire des cas (n-1) fois
fin faire
retourner (i>=n)
fin 1 retour + une comparaison (2 unités de temps)
Soit n la taille des données à traiter, on dit qu’une fonction f(n) est en O(g(n)) s’il existe un seuil
n0 à partir duquel la fonction f(.) est toujours dominée par g(.) à une constante multiplicative fixée c
près.
6.2 Exemples
a) Prouver que f(n)=3n+52 est de l’ordre de O(n)
Alors il faut trouver une constante c et un seul n0 / Ɐ n ≥ n0 , f(n)≥cg(n)
On remarque que : 3n+52≤4n c’est-à-dire si n≥ 52 alors on déduit que c=4 et que n0=52
Ou encore on peut dire que 3n+52≤ 5n c’est-à-dire si n≥ 52/2 alors on déduit que c=5 et que
n0=52/2=26
NB :On ne demande pas d’optimiser, il suffit de donner des valeurs qui fonctionnent
3
b) Démontrer que : f1(n)= 3n2+2n+8 est en O(n2)
Il faut chercher une constante c :
3n2+2n+8<=4n2
4n2-3n2-2n+8≥0 cad n2-2n+8 =( n-1) 2+9 ≥0 alors pour n0=1 l’inéquation est vérifiée
Donc il existe une constante c=4 et un n>n0=1 dont f1(n)≤4g(n)
c g(n)
Le traitement T qui est représenté par la boucle pour avec le compteur i nécessite :
-une initialisation de i à 1,
- n comparaisons de i avec N et
- n addition (+1) et affectation
- n affectations d’un zéro à un élément i (i[1,N]) du tableau R (n éléments).
Alors, T(n)= 3n+1 +n=4n+1, c / T(n) ≤cn. Donc T(n) est de complexité O(n)
7. Les règles générales de calcul de complexité d’un algorithme :
7.1 Règles de simplification de calcul d’un temps d’exécution
On calcule le temps d’exécution puis on fait des simplifications. Les quelques règles suivantes
permettent de simplifier les complexités :
-annuler les constantes additives (exemple f(n)=3n+5 on peut éliminer la constante additive 5)
-omettre les coefficients (exemple : 14n2 devient n2 )
-prendre en considération les termes dominants
Exemples : - na domine nb, si a > b (n2 domine n))
-exponentielle domine un polynôme (exemple : 3n domine n5 et également 2n)
- un polynôme domine un logarithme : n domine (log n).
Exemple
Soit à calculer un temps d’exécution d’un algorithme g(n)= 3n2+10n+10
-Eliminer les constantes additives : g(n)= 3n2+10n
-Annuler les coefficients (comme étant ils sont tous à 1) : g(n)= n2+n
-Retenir le plus haut degré g(n)=n2
On dit alors que cet algorithme possède une complexité g(n)=O(n2)
Détaillons plus
On suppose qu’on dispose d'un algorithme dont le temps d'exécution est décrit par la fonction
T(n) = 3n2+10n+10. L'utilisation des règles de la notation O nous permet de simplifier en :
O(T(n)) = O(3n2 + 10n + 10) = O(3n2) = O(n2)
-Pour n = 10 nous avons :
-Temps d'exécution pour le terme 3n2 : 3(10)2 / 3(10)2+10(10)+10 = 73,2%
4
-Temps d'exécution pour le terme 10n : 10(10) / 3(10)2+10(10)+10 = 24,4%
-Temps d'exécution la constante 10 : 10 / 3(10)2+10(10)+10 = 2,4%
2
En plus, le poids de 3n devient encore plus grand quand n augmente
Tel que le cas où n = 100, le temps d’exécution soit 96,7%. Alors, on peut négliger les quantités
10n et 10. Ceci explique les règles de la notation O.
7.2 Les règles de l’annotation O
La notation O est celle qui est le plus communément utilisée pour expliquer formellement les
performances d'un algorithme. Cette notation exprime la limite supérieure d'une fonction dans un
facteur constant. Les règles de la notation O sont les suivantes :
-Les termes constants : O(c) = O(1)
-Les constantes multiplicatives sont omises :
O(cT ) = cO(T) = O(T)
-L'addition est réalisée en prenant le maximum :
O(T1) + O(T2) = O(T1 + T2) = max(O(T1),O(T2))
-La multiplication reste inchangée mais est parfois réécrite d'une façon plus compacte :
O(T1)*O(T2) = O(T1*T2)
-le cas d’une complexité constante
Les instructions de base (lecture écriture affectation) sont des instructions qui prennent un temps
d’exécution constant.
Exemple un algorithme qui saisit deux valeurs et affiche leur somme. Cet algorithme va contenir
deux lectures, une addition et un affiche (ou une addition, affectation puis affiche). Alors, 4 ou 5
opérations à effectuer. On dit donc que c’est un algorithme de complexité O(5) noté par O(1).
-Le cas d’une suite d’instructions :
Traitement 1 (instructions 1) T1(n) (exemple : remplissage d’un tableau O(T1)=O(n))
Traitement2 (instructions 2) T2(n) (exemple : le tri d’un tableau O(T2)=O(n2)) )
Le traitement réalisé par l’algorithme T(n)=T1(n)+T2(n)
O(T)=O(T1+T2)= max(O(T1),O(T2)) (exemple : max(O(n),O(n2))= O(n2))
-Le cas d’une instruction conditionnelle :
Si (condition) alors O(T1(n))
Traitement1 O(T2(n)) O(T)=O(T1(n))+max(O(T2(n)), O(T3(n)))
Sinon = max(O(T1(n)),O(T2(n)), O(T3(n)))
Traitement2 O(T3(n))
Finsi
-La cas d’une boucle :
On multiplie la complexité du corps de la boucle par le nombre d’itérations. Exemple pour la boucle
tant que, la complexité se calcule comme suit pour n itérations :
Tant que (condition) faire O(T1)
Traitement O(T2) O((T1(n)+T2(n)))
Fin faire
Remarque :
Pour calculer la complexité d’un algorithme il faut :
- calculer la complexité de chaque partie de l’algorithme.
- combiner ces complexités conformément aux règles (présentées ci-dessus)
- effectuer sur le résultat les simplifications possibles (présentées ci-dessus)
7.3 Les classes de complexité
Les algorithmes usuels peuvent être classés en un certain nombre de grandes classes de complexité.
Les complexités les plus utilisées sont :
5
- Constante : O(1) Accéder au premier élément d'un
ensemble de données
- Logarithmique : O(logn) Couper un ensemble de
données en deux parties égales, puis couper ces
moitiés en deux parties égales, etc.
- Linéaire : O(n) Parcourir un ensemble de données
- Quasi-linéaire : O(nlogn) Couper répétitivement
un ensemble de données en deux et combiner les
solutions partielles pour calculer la solution
générale
-Quadratique : O(n2) Parcourir un ensemble de
données en utilisant deux boucles imbriquées
- Polynomiale : O(nP) Parcourir un ensemble de
données en utilisant P boucles imbriquées
- Exponentielle : O(2n) Générer tous les sous-ensembles possibles d'un ensemble de données
7.4 Etude de quelques exemples de classes de complexité
a. La complexité linéaire
On demande de trouver la complexité de la fonction rechercheSeq qui permet la recherche d’une
valeur dans un tableau séquentiellement
Fonction rehercheSeq(T[100],x,n :entier) :booléen
Variable
i:entier
Début
i1 (1 fois)
Tant que (i<=n) et (T[i]<>x) faire
ii+1
fin faire
retourner (i<=n)
fin
Le nombre de comparaisons réalisées dans le meilleur des cas est O(1) et dans les pire des cas
pour un tableau de taille n la complexité de la recherche séquentielle est de l’ordre de O(n).
6
si (x<t[mil]) alors
finmil-1
sinon
debmil+1
finsi
mil(deb+fin) div 2
fin faire
retourner (t[mil]=x)
fin
Le tableau de 8 éléments
Cet algorithme impose dans la démarche de découper à chaque fois le tableau en deux jusqu’à
atteindre un seul élément. Soit un tableau de N éléments avec 2 p-1N2p. Le nombre des étapes
nécessaires sera le nombre entier p qui est immédiatement plus grand que log2(N).
Exemple : pour n=16 on a besoin de 4 quand
Pour n=1000 le nombre d’étapes nécessaires est p tel que 2p-1n2p
On a 29<1000<210 alors le traitement est réalisé p=10 fois.
7
- la taille du tableau à trier est n.
- On a deux boucles imbriquées : La première indique l'élément suivant à insérer dans la partie
triée du tableau. Elle effectuera n - 1 itérations puisque le premier élément est déjà trié. Pour
chaque élément donné par la première boucle, on fait un parcourt dans la partie triée pour
déterminer son emplacement.
- Calcul de la complexité:
® Au meilleur des cas : le cas le plus favorable pour cet algorithme est quand le tableau est
déjà trié (de taille n). uniquement la boucle externe qui va fonctionnée alors (n-1) itérations
donc il s’agit d’une complexité de O(n)
® Au pire des cas : Le cas le plus défavorable pour cet algorithme est quand le tableau est
inversement trié
on fera une itération (1seul décalage) pour le 1er élément, deux itérations (deux décalages)
pour le 2ème et ainsi de suite pour les autres éléments.
Alors 1+2+3+4+…+(n-1)
Il s’agit d’une suite arithmétique de raison 1 de 1er terme 1 et du dernier terme n-1
Nombre de terme (dernier terme +premier terme)/2= ((n-1)-1+1) ((n-1)+1)/2
=n(n-1)/2=1/2(n2-n)
2
Alors la complexité est O(n )
8
9