Upload
others
View
5
Download
4
Embed Size (px)
Citation preview
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros
ANALYSE D’ALGORITHMES
Analyse d’algorithmes
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros ii
Questions fondamentales de notre vie professionnelle :? Ca va prendre combien de temps de faire ce calcul ?? Pourquoi mon code plante avec OutOfMemoryError ?�on a besoin de principes pour etudier la performance d’algorithmes
performance : temps de calcul, usage de memoire, usage d’autres ressources (caches,entree-sortie, resaux. . . )
→ importance theorique (theorie de complexite)
→ importance pratique : on veut une approche scientifique de caracteriser etpredire la performance
Temps de calcul — demarche scientifique
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros iii
modele→ prediction→ experience
1. definir : modele de l’entree + notion de taille (modele permet la simulation)
2. identifier : partie criticale du code (pour un algorithme iteratif, cette partie est al’interieur de la boucle le plus profondement imbriquee)
3. modele de cout : operation typique (comparaison ou deplacement dans un tri,acces aux cases du tableau, operation arithmetique dans algorithme numerique, . . . )
4. donner la frequence d’operations typiques en fonction de la taille de l’entree
�Une bonne caracterisation du temps de calcul nous permet de le considerer comme un hypothese
scientifique testable sur le comportement de l’algorithme. Apres qu’on a implante l’algorithme,
on peut experiencer avec des entrees differentes, en mesurant le temps actuel d’execution, et en
comptant les operations typiques.
Meilleur, pire, moyen
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros iv
Typiquement, il y a beaucoup d’entrees possibles avec la meme taille n, et le tempsde calcul peut dependre de l’entree actuelle et non pas seulement de sa taille.
Temps de calcul T (n) pour entree de taille n :? meilleur cas : minT (n) parmi toutes entrees de taille n? pire cas : maxT (n) parmi toutes entrees de taille n? moyen cas : T (n) en esperance (notion probabiliste !)� il faut assumer une distribution sur entrees de taille n : p.e., permutation au
hasard pour moyen cas d’un tri� on peut egalement decrire l’ecart-type, et d’autres proprietes de T (n), ce
dernier considere comme une variable aleatoire avec la distribution implieepar l’entree + l’algorithme
Experimentation
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros v
on a un algorithme⇒ implementer + tester
experimentation avec plusieurs jeux d’entrees :simulation ou repositoire de benchmarks
evaluation des resultats :? developper un hypothese sur le comportement si on n’a pas une meilleure idee? valider une prediction developpeeon mesure :? temps actuel d’execution : il faut rapporter de l’information sur l’environne-
ment de test : CPU, RAM, systeme d’exploitation, . . .? compte d’operations : ne depend pas de l’environnementexperiences reproductibles !⇒ falsifiabilite de la prediction + verifiabilite de tests
Temps actuel de calcul
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros vi
? dans le code...long T0 = System.currentTimeMillis(); // temps de debut...long dT = System.currentTimeMillis()-T0; // temps (ms) depasse
// ou avec System.nanoTime() pour precision de 10−9s
? dans la ligne de commande (time)
? profilage de code dans l’IDE (Eclipse/Netbeans/. . . )
Nombre d’operations
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros vii
? dans le codeprivate static final boolean COUNT=true;private static int op_count=0; // nombre de comparaisonsprivate static void insert(double[] T, int n, double x){
// T[0]<=T[1]<=...<=T[n-1] deja trieint j=n;while(j>0 ) {if (COUNT) $op_count++;if (T[j-1]<= x) break;T[j]=T[j-1];j--;
}T[j]=x;
}public static void insertionSort(double[] T){
for (int n=1; n<T.length; n++) insert(T,n,T[n]);if (COUNT)
System.out.println(T.length+"\t"+op_count);}
? profilage avec l’IDE (par ligne ou methode)
Conception d’experiences
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros viii
1. repeter avec la meme taille⇒ moyen + dispersion statistique
2. repeter avec tailles differentes : doubler
notre hypothese T (n) ∼ a · nb : T (2n)T (n) ∼
a(2n)b
anb= 2b
→ visualiser sur log-log : la pente indique l’exposant b
Tri par insertion : experimentation
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros ix
Experiences : ordre aleatoire (chaque ordre egalement probable)tailles n = 500,1000,2000, . . . , chaque repete 100 fois,on compte les comparaisons
y = 0.4279x R� = 0.99394
0.001
0.01
0.1
1
10
100
1000
0.01 0.1 1 10 100 1000 10000
Temps (ms)
Comparaisons (millions)
� nombre de comparaisons est un bon indicateur du temps de calcul
Tri par insertion 2
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros x
y = 1E-07x2 + 0.0001x R� = 0.99999
0.01
0.1
1
10
100
1000
500 2000 8000 32000
temps moyen (ms)
n (nombre d'éléments à trier)
y = 0.2499x2 + 2.734x R� = 1
0.01
0.1
1
10
100
1000
10000
500 2000 8000 32000
opérations en moyenne (millions) M
illions
n (nombre d'éléments à trier)
� regression quadratique semble appropriee
Tri par insertion
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xi
Entree: T [0..n− 1] // {n > 0}1 for i← 1,2, . . . , n− 1 do2 x← T [i]; j ← i
3 while j > 0 && T [j − 1] > x do T [j]← T [j − 1]; j ← j − 1
4 T [j]← x
5 end
1. entree : taille n, elements distincts2. le plus frequemment execute : boucle interne3. operation typique : comparaison
meilleur cas : n− 1 comparaisons (deja trie)
pire cas :
Cpire(n) =n−1∑i=1
i =n(n− 1)
2=
1
2n2 −
1
2n ∼ n2/2
Tri par insertion – moyen cas
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xii
lors du placement du k-eme element (a l’indice T [k − 1]), le nombre de compa-raisons en moyenne :
tk =1
k·1+
1
k·2+· · ·+
1
k·(k−1)+
1
k·(k−1) =
k(k + 1)/2− 1
k=k + 1
2−
1
k
nombre de comparaisons en total :
Cmoyen(n) =n∑
k=1
tk =n∑
k=1
(k + 1
2−
1
k
)=n(n+ 3)
4−Hn
avec le nombre harmonique
Hn = 1 +1
2+
1
3+ · · ·
1
n∼ lnn
Donc, Cmoyen(n) ∼ n2/4
Notation tilde
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xiii
Definition [notations tilde et petit-o]. Pour deux fonctions f, g : N→ R, on ecrit
f(n) ∼ g(n) si et seulement si limn→∞
f(n)
g(n)= 1 � «f est asymptotiquement egal a g»
f(n) = o(g(n)
)si et seulement si lim
n→∞
f(n)
g(n)= 0 � «f est negligeable par rapport a g»
As is typical in such expressions, the terms after the leading term are relatively small (for exam-ple, when N = 1,000 the value of ! N 2/2 " N/3
499,667 is certainly insignificant by com-parison with N 3/6 ! 166,666,667). To allow us to ignore insignificant terms and therefore sub-stantially simplify the mathematical formulas that we work with, we often use a mathemati-cal device known as the tilde notation (~). This notation allows us to work with tilde approxi-mations, where we throw away low-order terms that complicate formulas and represent a negli-gible contribution to values of interest:
Definition. We write ~f (N ) to represent any function that, when divided by f (N ), approaches 1 as N grows, and we write g(N ) ~ f (N ) to indicate that g(N )/f (N ) approaches 1 as N grows.
For example, we use the approximation ~N 3/6 to de-scribe the number of times the if statement in ThreeSum is executed, since N 3/6 ! N 2/2 " N/3 di-vided by N 3/6 approaches 1 as N grows. Most of-ten, we work with tilde approximations of the form g (N) ~af (N ) where f (N ) = N b (log N ) c with a, b, and cconstants and refer to f (N ) as the order of growth of g (N ). When using the logarithm in the order of growth, we gener-ally do not specify the base, since the constant a can absorb that detail. This usage covers the relatively few functions that are commonly encountered in studying the order of growth of a program’s running time shown in the table at left (with the exception of the exponential, which we defer to CONTEXT). We will describe these functions in more de-tail and briefly discuss why they appear in the analysis of algorithms after we complete our treatment of ThreeSum.
function tildeapproximation
orderof growth
N 3/6 ! N 2/2 " N/3 ~ N 3/6 N 3
N 2/2 ! N/2 ~ N 2/2 N 2
lg N + 1 ~ lg N lg N
3 ~ 3 1
Typical tilde approximations
order of growth
description function
constant 1
logarithmic log N
linear N
linearithmic N log N
quadratic N 2
cubic N 3
exponential 2 N
Commonly encounteredorder-of-growth functions
Leading-term approximation
N 3/6
N (N! 1)(N! 2)/6
166,167,000
1,000
166,666,667
N
1791.4 Q Analysis of Algorithms
n3/6− n2/2 + n/3 ∼ n3/6n2/2− n/3 = o(n3)
Ordre de croissance
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xiv
On peut caracteriser la croissance d’une fonction quelconque f en choisissant unefonction g t.q.
∃c ∈ R+ : f(n) ∼ c · g(n) �«f est de meme ordre de croissance que g»
Ici, on veut choisir g a la carte, sur une echelle standard de fonctions communes :chaque ordre est negligeable par rapport aux ordres superieurs
croissance g(n)constante 1 = o(logn)logarithmique logn = o(n)lineaire n = o(n logn)linearithmique n logn = o(n2)quadratique n2 = o(n3)cubique n3
polynomiale na logb n = o(An) ∀a, b ∀A > 1exponentielle 2n,3n, en, . . . = o(n!)
�c’est juste les ordres les plus communs (p.e., n log2(n)log logn
est un ordre de croissance assez rarement vu)
�la base du logarithme est omise dans l’ordre de croissance : pour tout a, b > 1on a loga n = c · logb n avec constante c = loga b qui ne depend pas de n
Tri par tas : analyse
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xv
HEAPSORT(A[1..n]) // tri du tableau A[1..n]H1 for i← bn/2c, . . . ,1 do sink(A[i], i, A, n) // heapifyH2 for i← n, . . .2 doH3 echanger A[1]↔ A[i]H4 sink(A[1],1, A, i− 1)
structure du tas binaire sur n elements : arbre binaire complet
operations a compter : affectations dans sink(x, i, . . . ) = hauteur du nœud i
heapify : on definitH(n) = somme des hauteurs dans le tas avec n nœuds internes
nombre d’affectations au total : H(n)
Somme des hauteurs
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xvi
1 2 3 4 5 6 7
8 9 10 11
12 13 14 15
+1 +2 +1 +3 +1 +2 +1
+4 +1 +2 +1
+3 +1 +2 +1
11 01 1
1 0 01 0 11 1 01 1 1
1 0 0 01 0 0 11 0 1 01 0 1 11 1 0 01 1 0 11 1 1 01 1 1 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+1
+2
+1
+3
+1
+2
+1
+4
+1
+2
+1
+3
+1
+2
+1
somme des hauteurs de noeuds dans un arbre binaire complet
affectation de bits pour compter en binaire
�meme que le nombre de bits a bousculer quand on compte jusqu’a n
compter jusqu’a n = 2t : H(1) = 1;H(2t) = 2 ·H(2t−1)+1 avec solutionH(2t) = 2 · 2t − 1 pour t ≥ 0.
Somme des hauteurs 2
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xvii
compter jusqu’a 2t ≤ n < 2t+1 (avec t = blgnc)
ecrire n =∑ti=0 bi2
i, bi ∈ {0,1} avec sa representation binaire
H(n) = btH(2t)+bt−1H(2t−1)+ . . .+b0H(20) = 2n−t∑
i=0
bi︸ ︷︷ ︸poids binaire de n
Preuve alternative : credit-debit, pour compter de 0 a n, il faut payer $1 pourchaque operation de bit.? mettre $1 a cote chaque fois bit incremente 0→ 1 w? recuperer quand 1→ 0 est necessaire sur ce bit? apres n incrementation, on a depense 2n ($1 pour 0 → 1, $1 mis a cote), et il
reste ‖n‖ =∑ti=0 bi sur le compte d’epargne
⇒ H(n) = 2n− ‖n‖.
�cout amorti d’incrementation binaire est 2n−‖n‖n ≤ 2− 1
n
Tri par tas : analyse 2
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xviii
apres heapify, on appelle sink sur (n− 1), (n− 2), (n− 3), . . . ,1 elements
hauteur de l’arbre binaire complet avec k > 0 nœuds internes = 1 + blg kc
nombre bits pour ecrire k > 0 en binaire : 1 + blg kc
S(n) = somme des bits dans les representations binaires de 1,2, . . . , n− 1 :
S(2t) =t−1∑i=0
2i(i+ 1) = (t− 1)2t + 1
S(n) = S(2t) +(n− 2t
)(1 + t) {t = blgnc}
S(n) = n(t+ 1
)− 2t+1 + 1 {lgn = t+ u}
S(n) = n lgn− n (u+ 21−u − 1)︸ ︷︷ ︸∈[0.9139··· ,1]
+1
Tri par tas : conclusion
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xix
Thm. Le tri par tas sur n elements fait ∼ 2n lgn comparaisons au pire.
Preuve. Pendant heapify, on fait 2(H(n) − n) ∼ 2n comparaisons. Ensuite,le nombre de comparaisons est 2
(S(n)− n
)au pire (2 enfants inspectes sauf a la
derniere iteration). Au total, c’est ∼ 2S(n), or S(n) ∼ n lgn. �
Diviser pour regner
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xx
divide-and-conquer
Demarche algorithmique a un probleme de structure recursive :
? partitionner le probleme dans des sous-problemes similaires,? chercher la solution optimale aux sous-problemes par recursion,? combiner les resultats.
Recursion pour temps de calcul
T (n) = τpartition(n) +∑
i=1,...,m
T (ni)︸ ︷︷ ︸m sous-problemes
+τcombiner(n)
Recherche dichotomique
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xxi
recherche d’element x dans un tableau trie a[0..n− 1]
Algo BSEARCH(x, a[], i, n) // binary search// cherche element x dans l’intervalle
{a[i], a[i+ 1], . . . , a[i+ n− 1]
}Entree : valeur recherchee x, tableau a[], indice de depart i ≥ 0, longueur n ≥ 0Sortie : indice j avec i ≤ j < i+ n t.q. x = a[j], ou valeur negative s’il n’existe pas
B1 if n = 0 then return −(i+ 1) // cas terminal : echec, valeur retournee < 0B2 m = i+ b(n− 1)/2c // indice de l’element au milieuB3 if x < a[m] then return BSEARCH
(x, a, i, b(n− 1)/2c
)B4 else if x > a[m] then return BSEARCH
(x, a,m+ 1, d(n− 1)/2e
)B5 else return m // cas terminal x = a[m] : succes
echec — nombre de comparaisons au pire (appels recursifs de Ligne B4)en notant d(n− 1)/2e = bn/2c :
Cn =
0 {n = 0}Cbn/2c+ 2 {n > 0}
→ Cn = 2(1 + blgnc
)(deux fois la longueur de l’encodage binaire de n)
Fusion de deux tableaux
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xxii
Algo FUSION(A[0..n− 1], B[0..m− 1]) // A,B : tableaux triesF1 initialiser C[0..n+m− 1] // on place le resultat dans CF2 i← 0; j ← 0; k ← 0 // i est l’indice dans A ; j est l’indice dans BF3 while i < n && j < m doF4 if A[i] ≤ B[j] then C[k]← A[i]; i← i+ 1F5 else C[k]← B[j]; j ← j + 1F6 k ← k + 1F7 while i < n do C[k]← A[i]; i← i+ 1; k ← k + 1F8 while j < m do C[k]← B[j]; j ← j + 1; k ← k + 1
Temps de calcul : (n+m) affectations, et (n+m− 1) comparaisons (au pire)
Tri par fusion
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xxiii
9 6 3 0 2 1 8 7 5 4
9 6 3 0 2 1 7 5 4
division 50-50% sans réarrangement
récursion
0 2 3 6 9 1
récursion
4 5 7 8
fusionner en O(n)
8
n/2 éléments n/2 éléments
0 1 2 3 4 5 6 7 8 9
Algo MERGESORT(A[0..n− 1], g, d) // appel initiel avec g = 0, d = n
// recursion pour trier le sous-tableau A[g..d− 1]M1 if d− g < 2 then return // cas de base : tableau vide ou un seul elementM2 m←
⌊(d+ g)/2
⌋// m est au milieu
M3 MERGESORT(A, g,m) // trier partie gaucheM4 MERGESORT(A,m, d) // trier partie droiteM5 FUSION(A, g,m, d) // fusion des resultats
Tri par fusion : analyse
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xxiv
nombre de comparaisons au pire pour n elements :
C(n) =
0 {n = 0,1}C(bn/2c
)+ C
(dn/2e
)+ (n− 1) {n > 1}
on peut ecrire un petit programme pour calculer C(n) a n = 0,1,2,3, . . . !
2
8
32
128
512
2048
8192
32768
131072
2 8 32 128 512 2048 8192
n
C(n) n lg(n) 6n n
Somme des bits
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xxv
Combinatorial correspondence
SN = number of bits in the binary rep. of all numbers < N
11011
100101110111
1000100110101011110011011110
11011
100101110111
1000100110101011110011011110
11011
100101110111
1000100110101011110011011110
5� 1
Same recurrence as mergesort (except for �1):
= + +
11011
100101110111
1000100110101011110011011110
:�5/2� :�5/2�
:5 = :�5/2� + :�5/2� +5� 1
*5 = :5 +5� 136
longueur totale desrepresentations binaires1, . . . , n− 1 :meme recurrence que lescomparaisons dans le tri parfusion !
on sait la solution exacte :
C(n) = S(n) = n lgn− n (u+ 21−u − 1)︸ ︷︷ ︸∈[0.9139··· ,1]
+1
avec u = {lgn} = lgn− blgnc
Tri par fusion
Analyse d’algorithmes ? IFT2015 H2019 ? UdeM ? Miklos Csuros xxvi
Theoreme. Le tri par fusion fait
C(n) = n lgn− nA({lgn}
)+ 1 ∼ n lgn
comparaisons au pire pour trier n elements, ou
{lgn} = lgn−blgnc ∈ [0,1) A(u) = u+21−u−1 ∈ [0.9139 · · · ,1]
2
8
32
128
512
2048
8192
2 8 32 128 512 2048 8192
nlg(n)-C(n) n C(n)-(nlg n-n)