Complexité

publicité
Complexité
1. Définition de la complexité
Les algorithmes se caractérisent par la taille des données qu'ils manipulent et l'ensemble
des traitements qu'ils opèrent sur ces données.
ex de taille :
•
nombres : le nombre lui même ou le nombre de bits (nb de chiffre en base 2)
•
liste, tableau, matrice, . . . : La nombre d'éléments
•
arbres : Nb de noeuds
•
graphes : Nb de noeud et/ou nb d'arêtes
ex de traitement :
•
affectations
•
allocation mémoire (pour l'espace)
•
comparaisons
•
arithmétique ,. . .
Pour un même problème, les algorithmes qui le résolve se classent selon leur complexité.
Définition (complexité) : La complexité d'un algorithme est la mesure du nombre d'opérations
fondamentales qu'il effectue sur un jeu de données. La complexité est exprimée comme une fonction
de la taille du jeu de données.
Soit Dn l'ensemble des données de taille n et T(d) le coût de l'algorithme sur la donnée d.
Complexité au meilleur : Tmin(n) = min d ∈ D T  d  : plus petit nombre d'opérations
qu'aura à exécuter l'algorithme sur un jeu de données de taille n. C'est la borne inférieure
de la complexité de l'algorithme sur un jeu de données de taille n.
n
Complexité au pire : Tmax(n) = max d ∈D T d  : plus grand nombre d'opérations qu'aura à
exécuter l'algorithme sur un jeu de données de taille n.
n
Complexité en moyenne : Tmoy(n) =
∑
d ∈D n
p d T d  : moyenne des complexités pour les
données de taille n avec p(d) la probabilité de voir apparaître la donnée d.
Attention : les complexités au meilleur et au pire ne sont que des indications, elles
montrent les limites au dessus et en deça desquelles l'algorithme n'ira pas. La complexité
en moyenne montre le comportement général de l'algorithme et ne donne une bonne
mesure que si le coût varie peu avec les données et si les cas extrêmes sont rares.
Dans la pratique on s'intéresse à la complexité au meilleur et au pire.
Définition (optimalité) : Un algorithme est dit optimal si sa complexité est la complexité minimale
parmi les algorithmes de sa classe.
2. Exemple : le tri insertion
•
•
principe : n éléments, dans un tableau T, indicés de 1 à n. On considère que les
éléments de 1 à j-1 sont triés (donc au départ j = 2). On insère le jième élément à la
bonne place par décalage.
Algorithme :
Tri Insertion
coût
pour j=2 à longueur(T)
fois
c1
n*
v = T[j]
c2
n-1
i = j-1
c3
n-1
tant que i>0 et T[i] > v
c4
n
∑ tj
**
j=2
T[i+1] = T[i]
c5
n
∑ t j−1
j=2
i=i-1
c6
n
∑ t j−1
j=2
T[i+1] = v
c7
n-1
* une affectation de plus pour le test de sortie de boucle (lorsque j = longueur(T)+1)
** tj correspond au nombre de fois que le test de la boucle tant que s'exécute (compris entre
1 et j).
•
Le coût total T  n est donc :
n
n
j=2
j =2
T  n=c 1 nc 2c 3c7 n−1c 4 ∑ t jc 5c6  ∑ t j−1
au meilleur (si le tableau est trié) : t j vaut toujours 1
T  n=c 1 nc 2c 3c7 c 4 n−1=c 1c 2c 3c 4c7  n−c 2c3 c 4c7 
au pire, lorsque le tableau est trié dans l'ordre décroissant, t j= j , on sait que :
n
∑
j=2
nn1
j=
−1 et
2
n
∑  j−1=
j=2
n n−1
2




n n1
nn−1
−1 c 5c 6 
2
2
c
c
1
c4
2
5
6
d'où : T  n= c 4c5c6  n c 1c2 c 3 − − c7  n−c 2c3c 4c 7 
2
2 2 2
donc : T  n=c 1 nc 2c 3c7 n−1c 4
T(n) est de la forme an 2bnc , c'est donc une fonction quadratique de n.
en moyenne : en moyenne, lors de l'insertion de l'élément v, il y a , dans la partie triée,
autant d'éléments supérieurs à v que d'éléments inférieurs à v et donc que t j= j/2 . Cela
conduit à une complexité quadratique similaire à celle du pire cas avec des facteurs ¼ au
lieu de ½.
La complexité en moyenne est parfois difficile à établir. Le cas « au pire » ou « au mieux »
est souvent représenté par une seule configuration qu'il convient alors d'examiner. Pour le
cas moyen, toutes les configurations doivent être considérées. Pour éviter une démarche
exhaustive, un étude probabiliste ardue doit parfois être menée.
3. Notations
•
•
•
Pour n∈ℕ
 g  n={ f n ∣ ∃c 1 , c 2  0 et n0 tel que 0c 1 g n f nc 2 g  n ∀ nn0 }
Une fonction f(n) appartient à  g n si elle peut être, à partir d'un certain n0,
encadrée par deux fonctions qui sont des multiples de g(n).
On dit que g(n) borne asymptotiquement f(n). On note abusivement
pour dire f n∈ g n .
exemple 1 : montrons que
f n= g n
2 2 1
2
n  n=n 
3
2
on doit déterminer trois constantes n 1, n2, c 0 avec
2 2 1
2
2
c 1 n  n  nc2 n pour nn 0
3
2
2 1
divisons par n2 : c 1  c 2
3 2n
•
On peut par exemple choisir c1 = 2/3, n0 = 3, d'où l'on déduit que l'inégalité fonctionne
pour c2 = 5/6.
2
3
2
exemple 2 : montrons que n3 ≠ n 2 . c 1 n n c 2 n en divisant par n2 il vient
c 1nc 2 on peut choisir c1 = 1 mais aucune constante n2 ne peut convenir car n est
arbitrairement grand.
•
Pour donner une borne supérieure ou inférieure asymptotique, on utiliser les notations
:
O g n={ f  n ∣ ∃c  0 et n0 tel que 0 f nc g  n ∀ nn0 } (borne supérieure)
Ω  g n={ f n ∣ ∃c  0 et n 0 tel que 0c g n f n ∀ nn0 } (borne inférieure)
4. Usages
•
•
•
•
•
Nous nous intéressons quasi exclusivement à la complexité en temps des algorithmes.
Il est parfois intéressant d'observer la complexité en espace mémoire, en bande
passante requise, etc.
Pour que les résultats de l'analyse d'algorithme soit comparable, il faut avoir un
modèle de la machine sur laquelle l'algorithme sera implémenté. On prendra comme
référence un modèle de machine à accès aléatoire et à processeur unique où les
opérations sont exécutées l'une après l'autre sans opérations simultanées.
Une complexité est généralement donnée en ordre de grandeur, lorsque n devient
grand, les termes les moins significatifs sont négligés. Ainsi pour le tri par insertion, on
notera :
- meilleur cas : n
- pire cas : n 2
- en moyenne : n 2
Les algorithmes sont en général comparés sur leur complexité au pire, aussi celle-ci est
donné en O(f(n)).
Classes de complexité :
–
constant : O1 On rencontre cette complexité quand toutes les instructions sont exécutées une
seule fois qu'elle que soit la taille n du problème.
–
sub-linéaire : O log n Ce cas de figure se rencontre quand la taille du problème est divisée
par une entité constante à chaque itération (ex : recherche dichotomique)
–
linéaire : O n boucle de 1 à n et le corps de la boucle effectue un travail de durée constante et
indépendante de n.
O n log n algorithmes quasi-linéaires où à chaque itération la taille du problème est
divisée par une constante avec à chaque fois un parcours linéaire des données.
–
–
polynomiale : O nk  concerne des algorithmes considérés comme lents lorsque k
> 3. boucles imbriquées chacune allant de 1 à n
exponentielle : O k n  pour k >= 2 donné, concerne des algorithmes considérés
–
comme impraticables (exemple : 2n pour les tours de Hanoï)
factorielle : O n !
log 2 n
n
nlog 2 n
n2
n3
2n
1
0
0
1
1
2
10
3,32
33,2
100
1 000
1 024
100
6,64
664
10 000
10
1 000
9,965
9965 1 000 000
10
6
1,26×10
9
30
∞
( 101000log  2
= 10300 )
10
1 000 000
19;931
19 931 568
109
29,89
29897352854
1018
1027
∞
2n
~+1
(x 2) (=> si 2x plus
de données,
on ajoute une
opération)
x2 + 2n
≈ x2
x4
x8
carré
1012
1018
∞
Si 109 opérations par secondes
log 2 n
n
nlog 2 n
n2
n3
2n

10-6 s
10-5 s
1 000
10-8 s
10-5 s
10-3 s
1s
∞
1 000 000
2 x 10-8 s
2 x 10-2 s
103 s = 16,6
min
31 ans
∞
109
3 x 10-8 s
30 s
109 sec = 31
ans
31 x 109
années
∞
100
5. Dernier exemple : tri rapide
écrire algorithme
complexité partition : O(n)
au pire : n appels à partition => O(n2)
−3
10
s
400×109
siècles
au mieux : tableau toujours coupé en deux : O(n log2 n)
en moyenne :
•
Idée : choisir le pivot aléatoirement, mais quelle sera alors la complexité attendue.
•
la complexité est fonction du nombre de comparaisons (si on considère l'arbre des
appels, à la racine, il y a n comparaisons, n-1 pour l'étage du dessous, etc., choisir un
pivot amène à réduire le nombre d'étages).
•
analyse : remarquons tout d'abord que toutes les comparaisons se font avec le pivot.
Soit x 1x 2 ...x n la suite des éléments triés. Quelle est la probabilité que les
éléments x i et x j avec i j soient comparés ? C'est la probabilité que x i ou
x j soit choisi comme pivot avant qu'ils soient séparés et cela par un pivot x k avec
ik  j . Dans toute suite x i , x i 1 ,... , x j , comme le pivot est choisi de manière
xi
x j soient comparés est
aléatoire uniformément la probabilité que
et
2 / j−i1
En prenant toutes les valeurs de i et j possibles, on trouve :
n−1
n
∑ ∑ 2/ j−i 1
i=1 ji
n−1 n−i1
= 2∑
i=1
n
∑
1/ k
k=2
n
avec
n
Hn=∑
k=1
1
k
le nième nombre harmonique
 2 ∑ ∑ 1/k
i=1 k=1
 2nHn
Puisque ln n≤Hn≤ln n  1 ,
tri rapide est : O n log n .
Hn=ln n1
donc le temps attendu de l'algorithme
Téléchargement