MPSI2 Complexit´e d’un algorithme Informatique
1 Introduction
1.1 Deux exemples
La fa¸con de programmer a une influence notable sur le temps de calcul et sur la gestion de la m´emoire. Afin de mieux
mesurer les enjeux de cette notion de complexit´e, consid´erons les deux exemples suivants.
Exemples : i) On souhaite simuler le comportement de particules de gaz en pla¸cant dans un fichier les positions initiales
(px, py, pz)et les vitesses initiales (vx, vy, vz). Un nombre flottant est coe sur 64 bits. Si l’on souhaite ´etudier un volume de
1litre d’un gaz parfait `a une temp´erature de 20C et `a une pression de 1013hPa, il va nous falloir :
1
24 ×6.02 ×1023 ×6×64 bits = 9.632 ×1024 bits
C’est-`a-dire 172To par habitant de la Terre.
ii) La suite d´efinie par Hn=
n
X
k=1
1
kdiverge vers +”`a la vitesse de” ln(n). Pour calculer la constante γavec
une pr´ecision de 20 d´ecimales apr`es la virgule, il nous faudrait environ 51 millions d’ann´ees sur un ordinateur standard.
Ces deux exemples montrent qu’il est fondamental de s’ineresser `a la place prise en m´emoire par les calculs que l’on
fait ainsi qu’au temps de calcul.
Principe de l’espace-temps informatique : pour gagner du temps de calcul, on doit utiliser davantage d’espace
m´emoire.
Dans la suite de ce chapitre, on s’int´eresse essentiellement `a la complexit´e en temps. C’est justifi´e par le faible coˆut de
l’espace m´emoire.
1.2 Point de vu pratique
L’acronyme FLOPS (FLoating-point Operations Per Second) d´esigne le nombre d’op´erations `a virgule flottante par
seconde, ce qui inclut toutes les op´erations qui impliquent des nombres r´eels. Un ordinateur personnel muni d’un micro-
processeur cadenc´e `a 2.5 GHz a une cadence th´eorique de 10 milliards de FLOPS.
Actuellement la plate-forme de calcul distribu´e BOINC totalise 8 ×1018 FLOPS.
Loi de Moore : `a coˆut constant la rapidit´e des processeurs double tous les 18 mois. Les capacit´es de stockage suivent
la mˆeme r`egle empirique.
Le temps d’ex´ecution d’un algorithme d´epend dans une large mesure du langage de programmation, de l’ordinateur et
du syst`eme d’exploitation utilis´es.
Ce chapitre ne s’int´eresse pas `a la vitesse de calcul d’un ordinateur, que l’on peut d’ailleurs mesurer en Python avec le
module time, mais plutˆot `a la complexit´e d’un algorithme d’un point de vue th´eorique.
2 D´efinition de la complexit´e
2.1 Exemple de la recherche des diviseurs
On cherche `a afficher la liste des diviseurs d’un entier naturel n. On peut ´ecrire l’algorithme na¨ıf suivant :
def diviseurs(n):
for iin r an ge ( 1 , n + 1 ) :
i f n % i == 0 :
print( i )
S’ineresser `a la complexit´e de cet algorithme revient `a compter le nombre d’op´erations qu’il effectue. Cet algorithme
calcule nrestes de divisions euclidiennes, effectue ncomparaisons et au plus naffichages. Empiriquement, c’est la division
euclidienne qui est la plus coˆuteuse en temps, il y a ndivisions euclidiennes.
1 Chapitre 6
MPSI2 Complexit´e d’un algorithme Informatique
On peut am´eliorer cet algorithme si l’on se souvient que si n=pq avec pnalors qn. Il suffit donc de chercher
chaque diviseur pinf´erieur ou ´egal `a net d’afficher ´egalement q=n/p. Voici une am´elioration du programme pr´ec´edent
qui tient compte de cette remarque :
import math
def d i v i s e u r s 2 ( n ) :
for iin range (1 , i n t ( math . s q r t ( n ) ) + 1 ) :
i f n % i == 0 :
print( i )
print( n // i )
Lors de l’ex´ecution de cette fonction, il y a E(n)divisions euclidiennes effectu´ees.
Conclusion : si l’on n´eglige les op´erations de comparaison et d’affichage et que l’on suppose que le temps de calcul pour
effectuer une division euclidienne est talors le temps d’ex´ecution de l’algorithme 1 est tn et celui de l’algorithme 2 est tn.
Cela peut repr´esenter un gain de temps cons´equent si nest grand.
2.2 D´efinitions et notation
Objectifs des calculs de complexit´e : -pouvoir pr´evoir le temps d’ex´ecution d’un algorithme
-pouvoir comparer deux algorithmes r´ealisant le mˆeme traitement
-garantir la s´ecurit´e d’un syst`eme de cryptographie
2.2.1 Taille du probl`eme
En g´en´eral, le temps d’ex´ecution d’un algorithme varie en fonction d’un param`etre d’entr´ee que l’on appelle la taille
du probl`eme. Dans l’exemple pr´ec´edent, la taille du probl`eme est l’entier ndont on souhaite trouver les diviseurs. En effet,
on a remarqu´e que le temps d’ex´ecution de l’algorithme est proportionnel `a nou `a n.
La taille du probl`eme sera parfois pr´ecis´ee dans l’´enonc´e mais dans certains cas ce sera `a vous de la choisir. Voici quelques
exemples de choix possibles.
Exemples : i) Lorsque le probl`eme d´epend d’un entier naturel n, il y a deux choix logiques : l’entier lui-mˆeme ou le
nombre de chiffres de n.
ii) Vous ´etudierez l’ann´ee prochaine des algorithmes permettant de trier des listes de nombres entiers.
La taille de la donn´ee sera le nombre d’´el´ements du tableau.
iii) Si vous ´etudiez un programme travaillant sur un texte, il sera naturel de prendre pour taille du probl`eme
le nombre de caract`eres du texte.
iv) Si vous travaillez avec des matrices carr´ees, il sera naturel de prendre le nombre de lignes de la matrice
comme taille du probl`eme.
2.2.2 Que compter ?
Dans l’exemple, nous avons choisi de nous concentrer uniquement sur le nombre de divisions euclidiennes effectu´ees et
de n´egliger le coˆut des autres op´erations.
En g´en´eral, nous comptons le nombre d’op´erations effectu´ees : additions, multiplications, comparaisons,
affectations... On peut ˆetre amen´e `a consid´erer que certaines op´erations sont n´egligeables par rapport `a d’autres, la plupart
du temps ce sera pr´ecis´e dans l’´enonc´e.
Exemple : Si l’on souhaite comparer plusieurs algorithmes de tris de listes d’entiers, on pourra d´enombrer les comparaisons
effectu´ees par ces algorithmes.
2 Chapitre 6
MPSI2 Complexit´e d’un algorithme Informatique
2.2.3 Notation
Dans l’exemple pr´ec´edent, avec notre algorithme optimis´e de recherche de diviseurs, nous avons vu que le temps de
calcul est proportionnel `a tn. Le param`etre test le temps mis par Python pour effectuer une division euclidienne, ce r´eel
d´epend bien ´evidemment de la machine utilis´ee. Ce param`etre ne change pas l’efficacit´e intrins`eque de notre algorithme.
Ce qui nous ineresse n’est pas un temps pr´ecis d’ex´ecution mais un ordre de grandeur de ce temps
d’ex´ecution en fonction de la taille des donn´ees.
On dira que notre algorithme a une complexit´e en O(n) (se lit grand o).
Une derni`ere notion `a consid´erer est celle du terme dominant dans le temps d’ex´ecution d’un algorithme. Par exemple,
si l’on a d´etermin´e que le temps d’ex´ecution est proportionnel `a n2+ 3nd`es que la taille ndevient grand, il est connu que
le terme 3nest n´egligeable devant n2. On dira que n2+ 3nest un O(n2).
Remarque : Toutes ces notations seront pr´ecis´ees dans le cours de math´ematiques.
2.3 R´ecapitulatif des complexit´es usuelles
Voici les ordres de grandeur des temps d’ex´ecution que l’on rencontre en pratique pour un probl`eme de taille n= 106
sur un ordinateur personnel effectuant 1 milliard d’op´erations par seconde.
Nom courant Temps Remarques
O(1) temps constant 1ns le temps d’ex´ecution ne d´epend pas de la taille des donn´ees : rare.
O(log(n)) logarithmique 10ns la base du logarithme n’a pas d’importance
O(n) lin´eaire 1ms
O(n2) quadratique 15min cette complexit´e n’est pas acceptable pour des donn´ees de taille >106
O(nk) polynomiale 30 ans si k= 3 il n’est pas rare de voir des complexit´es en O(n3) ou O(n4)
O(2n) exponentielle 10300000 ans impraticable sauf pour des tailles de donn´ees tr`es petites
Remarques : i) On peut encore faire bien pire, la fonction d’Ackerman est une fonction de N2dans Nefinie par :
Ack(m, n) = n+ 1 si m= 0
Ack(m, n) = Ack(m1,1) si n= 0 et m > 0
Ack(m, n) = Ack(m1, Ack(m, n 1)) sinon
Cette fonction est parfois utilis´ee comme programme de test d’une impl´ementation d’un langage de programmation. Le
calcul de Ack(4,4) met d´ej`a `a rude ´epreuve Python !
ii) L’hypoth`ese P=NP est l’un des probl`emes d’informatique th´eorique les plus importants. C’est l’un
des 7probl`emes du milenaire, il est dot´e d’une r´ecompense d’un million de dollars. L’´enonc´e de ce probl`eme est difficile `a
comprendre sans pr´erequis, disons simplement que c’est un probl`eme th´eorique concernant la complexit´e d’algorithmes.
3 Chapitre 6
MPSI2 Complexit´e d’un algorithme Informatique
2.4 Diff´erentes nuances de complexit´e
Pour deux donn´ees de mˆeme taille un algorithme n’effectue pas n´ecessairement le mˆeme nombre d’op´erations ´el´ementaires.
Consid´erons le test de primalit´e suivant :
premier = True
for iin range (2 , i n t ( s q r t ( n ) ) + 1 ) :
i f n % i == 0 :
premier = F a ls e
break #permet d i n te r ro mpr e l a b o u c l e
Si nest un nombre premier sup´erieur `a 3, il faudra effectuer E(n)1 divisions euclidiennes. Si on lance le programme
avec n+ 1, il va s’arrˆeter d`es la premi`ere it´eration puisque n+ 1 est divisible par 2. Ainsi pour des donn´ees de taille similaire
le nombre d’op´erations effectu´ees par l’algorithme est tr`es diff´erent.
Le plus souvent, on cherche un majorant du temps d’ex´ecution, c’est donc la complexit´e dans le pire des cas qui
nous ineresse. La complexit´e dans le meilleur des cas est anecdotique mais elle peut donner un minorant du temps
d’ex´ecution d’un algorithme.
Remarque : Il est possible de formaliser ces notions. On note Dl’ensemble des donn´ees sur lesquelles op`ere un algorithme.
Pour nN, on note Dnl’ensemble des donn´ees de taille n. On note c(d)le nombre d’op´erations ´el´ementaires effectu´ees par
l’algorithme lorsqu’il est appel´e avec la donn´ee d.
La complexit´e dans le pire des cas est max{c(d), d ∈ Dn}.
La complexit´e dans le meilleur des cas est min{c(d), d ∈ Dn}.
La complexit´e en moyenne est : X
d∈Dn
Pn(d)c(d)o`u Pn(d)esigne la probabilit´e que dsoit envoy´e comme param`etre. Si
les appels sont ´equiprobables, on a : Pn(d) = 1
Card(Dn).
2.5 Quelques complexit´es
Afin d’avoir quelques points de rep`ere, voici quelques complexit´es usuelles.
Les meilleurs tests de primalit´e d´eterministes ont une complexit´e en O(log(n)6) o`u nesigne l’entier dont on veut tester
la primalit´e.
La multiplication de deux matrices carr´ees de taille navec la m´ethode na¨ıve a une complexit´e en O(n3) (si l’on compte
les multiplications). L’algorithme de Coppersmith-Winograd permet de multiplier deux matrices en O(n2,376).
Il existe des algorithmes permettant de trier une liste d’entiers `a n´el´ements en O(nln(n)), comme l’algorithme du tri
fusion. On sait d´emontrer que cette complexit´e est la meilleure possible.
3 Exemples de calculs de complexit´e
Dans ce paragraphe nd´esigne la taille de l’argument en entr´ee de l’algorithme et C(n) d´esigne le nombre d’op´erations
´el´ementaires effectu´ees.
3.1 Complexit´e lin´eaire
On consid`ere le programme suivant :
def f a c t o r i e l l e (n ) :
P = 1
for iin r an ge ( 2 , n + 1 ) :
P=P i
return(P)
On s’ineresse au nombre de multiplications en fonction de la donn´ee n. On a clairement C(n) = n1. Ainsi C(n) = O(n),
on dit que la complexit´e est lin´eaire.
4 Chapitre 6
MPSI2 Complexit´e d’un algorithme Informatique
3.2 Exponentiation rapide
Le but du probl`eme est de calculer ano`u aest un flottant et nN. On cherche la complexit´e de ce probl`eme en terme
de multiplications selon la donn´ee en entr´ee : n. En effet, on suppose que l’op´eration a×ane d´epend pas de la valeur de a.
3.2.1 ethode na¨ıve
Cela consiste `a utiliser la d´efinition an=a×a×... ×a
| {z }
nfois
. On a l’algorithme suivant :
def exp1 ( a , n ) :
P = 1
for iin r an ge ( n ) :
P=P a
return(P)
Comme dans l’exemple pr´ec´edent, cet algorithme pr´esente une complexit´e en O(n). Nous allons voir qu’il est possible
de l’am´eliorer.
3.2.2 Exponentiation rapide
L’algorithme qui suit est bas´e sur la remarque :
(an= (a2)n
2si nest pair
an=a(a2)n1
2si nest impair
On peut ´ecrire une fonction qui utilise ce principe :
def ex po ra pi de ( a , n ) :
r = 1
while n>0 :
i f n % 2 == 1 :
r = a r
a=a a
n = n // 2
return( r )
Voil`a un exemple qui d´ecrit le fonctionnement de l’algorithme pour a= 2 et n= 10.
r= 1
a= 2
n= 10
r= 1
a= 4
n= 5
r= 4
a= 16
n= 2
r= 4
a= 256
n= 1
r= 1024
a= 256
n= 0
Vous pouvez v´erifier qu’avec ce proc´ed´e, nous avons effectu´e 6 multiplications. D’ailleurs, il est possible d’ajouter un
compteur, i, dans notre fonction qui va ˆetre incr´ement´e de 1 d`es que l’on effectue une multiplication afin de connaˆıtre le
nombre de multiplications au total.
def ex po ra pi de ( a , n ) :
r = 1
i = 0
while n>0 :
i f n % 2 == 1 :
r = a r
i = i + 1
a=a a
i = i + 1
n = n // 2
return( r , i )
5 Chapitre 6
1 / 8 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !