Structures de données IFT-2000 Abder Alikacem Analyse dalgorithmes Département dinformatique et de...
-
Upload
irenee-delaunay -
Category
Documents
-
view
105 -
download
0
Transcript of Structures de données IFT-2000 Abder Alikacem Analyse dalgorithmes Département dinformatique et de...
Structures de données
IFT-2000
Abder AlikacemAbder Alikacem
Analyse d’algorithmes
Département d’informatique et de génie logiciel
! +
Édition Septembre 2009
Plan
Notions d’analyses d’algorithmes Introduction Efficacité des algorithmes Analyse d’algorithmes Notation Ω (big-omega) Notation Θ Notation o (little-oh) Notation O (big-oh) Baromètres Comparaison entre les classes de complexité Règles de simplification Espace mémoire Compromis espace/temps
Algorithmique
Conception de méthodes pour la résolution de problèmes
Description des donnéesDescription des méthodesPreuve de bon fonctionnement
Complexité des méthodes
Efficacité : temps de calcul, espace nécessaire, ...Complexité intrinsèque, optimalité
Réalisation - implémentation
Organisation des objetsOpérations élémentaires
Efficacité des algorithmes
Habituellement on mesure l’efficacité d’un algorithme (correct) par sa vitesse.
• C’est-à-dire la durée que met l’algorithme à produire ses résultats.
On veut savoir combien de temps cela prend de résoudre une instance I du problème P:
• données(I) + Algorithme(P) ==> résultat(I).• temps mis ?
Efficacité des algorithmes
Ici, on s’intéresse au temps de calcul pour résoudre I:• en microsecondes, cycles d’horloge, nombre d’instructions
exécutées, etc..On prend en compte la taille des données(I):
•en bits, entiers, nombres d’enregistrements...Parfois, on considère aussi la mémoire nécessaire.
Efficacité des algorithmes
Approche empirique: mesure de performances.• essayer l’algorithme sur différents jeux de données bien
choisis.Avantages:
• résultats réalistes. Inconvénients:
• coûteux et long• dépend du processeur, de l’OS et de la charge • dépend de l’implémentation• pas toujours généralisable.
Efficacité des algorithmes
Approche algorithmique:• estimer le nombre de pas de l’algorithme en fonction de la taille des
données.Avantages:
• résultats généraux: on ne dépend pas du processeur, de l’OS ou de l’implémentation
• Estimation rapide et peu coûteux • évite de se fourvoyer.
Inconvénients:• prédictions approximatives.
Efficacité des algorithmes
Les approches empiriques et algorithmique sont complémentaires.• Utiliser l’approche algorithmique pour déterminer comment le
temps de calcul varie avec la taille des données.• Utiliser l’approche empirique afin d’obtenir un temps d’exécution
précis. (associé à une implantation, à un système d'exploitation , et à un type de compilateur particuliers)
Avantage: estimer le temps que prend l’algorithme pour des tailles de données plus grands que ceux des tests effectifs.
Efficacité des algorithmes
Comment choisir parmi les différentes approches pour résoudre un problème?
Exemple: Liste chaînée ou tableau?
2 objectifs à atteindre:1. Concevoir un algorithme facile à comprendre, coder et
déboguer.2. Concevoir un algorithme qui utilise de façon efficace les
ressources de l’ordinateur.
Efficacité des algorithmes
Objectif (1): concerne le génie logiciel
Objectif (2): Algorithmes et structures de données.
Lorsque l’objectif (2) est important, comment peut-on mesurer l’efficacité d’un algorithme?
Analyse d’algorithme
Analyse empirique: exécuter le programme Analyse assymptotique d’algorithmes
Ressources critiques: temps, espace mémoire,...
Facteurs affectant le temps d’exécution:machine, language, programmeur, compilateur, algorithme et structure de données.
Le temps d’exécution dépend du volume de l’entrée.
Analyse d’un algorithme
Analyse détaillée :• Avantage :Très précise• Désavantage : Long à calculer
Solution: Analyse asymptotique du comportement de l’algorithme lorsque le(s) paramètre(s) de l’algorithme tendent vers l’infini:
• Avantage: Parfois facile à calculer• Désavantage: Parfois moins précis
Mesure indépendante de l'implémentation : Temps d'exécution d'un algorithme = fonction(taille du problème)
Notation (big-omega)
Détermine une borne inférieureDéfinition formelle : f(n) = (g(n)) s’il existe deux constantes positives
n0 et c tel que cg(n) <= f(n) pour tout n>n0
f(n) = (g(n))
n
tem
ps
cg(n)
f(n)
n0
Notation (big-omega)
Étant donné deux fonctions f(n) et g(n), f(n) = (g(n)) ssi:• b > 0, n, f(n) / g(n) >= b
• Limn f(n) / g(n) +
Exemple
f(n) = 3n2+6n+4 et g(n) = n+3 limn f(n) / g(n) =
3n2+6n+4 est (n+3)
3n2+6n+4 est (n)
On dit « f(g) est en oméga g(n) »
Notation
Relation d’équivalence, correspond à la complexité exacte
Définition formelle : f(n) = (g(n)) s’il existe trois constantes positives n0,c1 et c2 tel que c1g(n) <= f(n) <= c2g(n) pour tout n>n0
f(n) = (g(n))
n
tem
ps
c1g(n)
f(n)
n0
n0
c2g(n)
Notation
Étant donné deux fonctions f(n) et g(n), f(n) = (g(n)) ssi: a,b > 0, n, a <= f(n) / g(n) <= b
• Limn f(n) / g(n)
Exemple:f(n) = 3n2+6n+4 et g(n) = n2+3
limn f(n) / g(n) = 3n2+6n+4 est (n2+3)
3n2+6n+4 est (n2)
Autre propriété:
f(n) = (g(n)) ssi f(n) = O(g(n)) et f(n) = (g(n))
Notation o (little-oh)
Détermine une borne supérieure stricteDéfinition formelle : f(n) = O(g(n)) s’il existe deux constantes positives
n0 et c tel que f(n) < cg(n) pour tout n>n0
f(n) = O(g(n))
n
tem
ps
cg(n)
f(n)
n0
Notation O (big-oh)
Détermine une borne supérieure Définition formelle : f(n) = O(g(n)) s’il existe deux constantes positives
n0 et c tel que f(n) <= cg(n) pour tout n>n0
f(n) = O(g(n))
n
tem
ps
cg(n)
f(n)
n0
Notation O (big-oh)
Cherche une fonction simple qui décrit le comportement de l’algorithme dans le pire cas.
• Exemples : O(n), O(n2),O(log n)L’analyse est simplifié selon les règles suivantes:
• Les constantes sont éliminées• Seul le monôme avec le degré le plus élevé est conservé
Exemple: f(n) = 3n2+5n+4 est O(n2)
0 10 20 30 40 50 600
500
1000
1500
2000
2500
3000
3500
4000
n (taille des données)
f(n) vs n2
f(n)
n2
f(n)
Exemple
void triSelection(int tab[MAXTAB], int n){
int PositionMin, temp, i, j;
for (i = n-1; i > 0; i--){
PositionMin = i;for (j = 0; j < i; j++){
if (tab[j] < tab[PositionMin]){
PositionMin = j;}
}temp = tab[i];tab[i] = tab[PositionMin];tab[PositionMin] = temp;
}}
void triSelection(int tab[MAXTAB], int n){
int PositionMin, temp, i, j;
for (i = n-1; i > 0; i--){
PositionMin = i; //b1for (j = 0; j < i; j++){
if (tab[j] < tab[PositionMin]){
PositionMin = j;}
}temp = tab[i];tab[i] = tab[PositionMin];tab[PositionMin] = temp;
}}
// i * a
//b2
Qu’est-ce qu’un baromètre?Comment ça fonctionne?Comment choisir le choisir ?
Baromètres
Baromètres
Qu’est-ce qu’un baromètre?•C’est une instruction qui s’exécute au moins autant de fois que
chacune des autres.Comment ça fonctionne?:
•Sélectionne un ensemble d’instructions significatives B={b1…bk}•On détermine le nombre d’exécution de chacun des baromètres
dans B•Temps total est la somme du nombres de d’exécution de chaque
baromètreComment choisir l’ensemble B?
•Mettre systématiquement certains types d’instructions(boucles,conditions,etc.)
•Estimer leurs nombres d’exécution maximal et minimal selon que l’on calcul le meilleur ou le pire cas.
•Simplifier B en gardant seulement les instructions qui s’exécutent le plus souvent.
Baromètres
Boucle tant que (pour): chaque fois qu’on passe dessus, il s’exécute le nombre de fois que la condition est vraie+1 (quand la condition est fausse).
Bloc interne d’un while: chaque fois qu’on passe sur le while, on passe sur ses instructions autant de fois que la condition est vraie.
Bloc interne d’un si: chaque fois qu’on passe sur le si et que la condition est vraie, on passe sur ses instructions
Autres instructions: chaque fois qu’on passe dessus, elles s’exécutent une fois.
Exemple (suite)
for (i = n-1; i>0; i--)
{Coût b1 /* PositionMin = i */
Coût i*a; /* pour exécuter la boucle interne*/
Coût b2; /* pour l'échange de tab[i] et tab[PositionMin] */
}
Exemple (suite)Exemple (suite)
1
1
)(n
i
baiS
b = b1 + b2
1
1
1
1
n
i
n
i
biaS
bnnnaS )1(2
)1(
bnabnaS 2
2
2
f(n) = an2 + bn + c
a = 0.0001724, b = 0.0004, c = 0.1
n f(n) an2 % du n2
125 2.8 2.7 94.7
250 11.0 10.8 98.2
500 43.4 43.1 99.3
1000 172.9 172.4 99.7
2000 690.5 689.6 99.9
Retour sur la notation O( ) (big-oh)
Évaluer le coût d'un algorithme Rechercher la fonction g(n) qui est la plus proche au dessus ou égale à f(n). Nous dirons alors f(n) est O(g(n)).
f(n) = O(g(n))
n
tem
ps
cg(n)
f(n)
n0
Notation O(g(n)) (big-oh)
Pour un nombre n assez grand f(n) an2
Temps d'exécution d'un algorithme A est f(n) = an2 + bn + c
g(n) = n2
On écrit : A est O(n2) On lit : l'algorithme A tourne en O(n2)
Classes :O(1), O(n), O(n2), O(n3), O(log n), …
f(n)
1
log n
n2n2n
Notation O(g(n)) (big-oh)
Classes :O(1), O(n), O(n2), O(n3), O(log n), …
n
Comparaison entre les classes
0
2
4
6
8
10
12
1 2 3 4 5 6 7 8 9 10
x
log( x )
xx VSVS log(x)log(x)
Comparaison entre les classes
0
5
10
15
20
25
30
35
40
45
50
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
x
x log( x )
xx VSVS x log(x)x log(x)
Comparaison entre les classes
0
50
100
150
200
250
300
350
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
x2
x log( x )
xx22 VSVS x log(x)x log(x)
Comparaison entre les classes
0
1000
2000
3000
4000
5000
6000
7000
8000
9000
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
x
x2
x3
xx VSVS xx22 VSVS xx33
Comparaison entre les classes
0
200000
400000
600000
800000
1000000
1200000
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
x3
2n
O(1) < O(log(n)) < O(n) < O(nlog(n)) < O(n2) < O(n3) < O(2n) < O(10n)
Comparaison entres les classes
O(1). Constant ou borné parfait.O(log(n)). Logarithmique excellentO(n). Linéaire très bonO(n log(n) ) bon.O(na) polynomial acceptableO(an) exponentiel inacceptableO(n!) factoriel beurk.
Augmenter la puissance du PC ?
0
5
10
15
20
25
30
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
x
x log( x )
x log( x )/1,2
Augmenter la puissance du PC
0
50
100
150
200
250
300
350
400
450
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
x2
0,5
Meilleur algorithme ou ordinateur?
On suppose que l’ordinateur utilisé peut effectuer 106 opérations à la seconde
Exemple (suite et fin)
1
1
)(n
i
baiS
b = b1 + b2
1
1
1
1
n
i
n
i
biaS
bnnnaS )1(2
)1(
bnabnaS 2
2
2
L’algorithme est en O(n2)
int minimumOn2(int tableau[],int taille){ int i,j; for(i=0;i<taille;i++) { j=0; while(j<taille && tableau[i]<=tableau[j] ) {
j++; } if(j == taille) return tableau[i]; } return tableau[i];}
int minimumOn(int tableau[],int taille){ int i,min = tableau[0]; for(i=0;i<taille;i++) {
if( tableau[i]<min) min = tableau[i]; } return min;}
Algorithme #1
Algorithme #2
Exemple: chercher le minimum dans un tableau d’entiers
Autres exemplesFusionner(x,y)
n = taille(x)+taille(y)pour i=1:n ….
v(i) = …..…..
fin
Résoudre(P(n))
Si n = 1 ,...c’est finiSinon
A=Résoudre(P(1:n/2))B=Résoudre(P(n/2+1:n))Fusionner(A,B)
pour i=1:n s = 0;pour j=i:n
s =s+A(i,j)*b(i)Finc(i)=s
fin
O(nlog2n)
O(n)
O(n2)Ab=c
Simplifier les séries
Sommes ou produits avec un nombre variable de termes.
Série Formule Résultat Exemple O()
constante k=1..N a aN 3+3+...+3(10 fois) N
somme de logs k=1..N log(k) log(N!) log(2)+log(3)+..log(100) N log(N)
arithmétique k=1..N k N(N+1)/2 1+2+...+10 N2
somme de carrés k=1..N k2 N(N+1)(2N+1)/6 1+22+32+..102 N3
somme de puissances
k=1..N ka (a entier) 1+23+33+..103 (a=3) Na+1
de polynômes de degré a
k=1..N Pa(k) k=1..N k(k+1)..(k+a) Na+1
géométrique binaire
k=0..N 2k 2N+1-1 1+2+4+..+128 2N
géométrique entière
k=0..N ak (a entier) (aN+1-1)/(a-1) 1+3+9+..+81 (a=3) aN
factorielle k=1..N k N!2N (N/e)N 1*2*..*100 NN+0.5
Pire cas, meilleur cas et cas moyen
Toutes les entrées d’une longueur donnée ne nécessitent pas le même temps d’exécution.
Exemple. Recherche séquentielle dans un tableau de taille n: Commencer au début du tableau et considérer
chaque élément jusqu’à ce que l’élément cherché soit
trouvé.
Meilleur cas: O(1)
Pire cas: O(n)
Cas moyen: O(n/2)
Règles de simplification
1. Toujours négliger les constantes multiplicatives:
2n2 = O(n2)
2. Négliger les termes d’ordre inférieur:
5n2 + 3n = O(n2) + O(n) = O(n2)
3. O(n2) x O(n3) = O(n5)
Règles de simplification
Si f(n) O(g(n))
et g(n) O(h(n)),
alors f(n) O(h(n)).
Règles de simplification
Si f(n) O(kg(n))
où k >0 est une constante
alors f(n) O(g(n)).
Règles de simplification
Si f1(n) O(g1(n))
et f2(n) O(g2(n)),
alors f1(n) + f2(n) O(max(g1(n), g2(n))).
Exemple: n + nlog n O(nlog n)
Règles de simplification
Si f1(n) O(g1(n))
et f2(n) O(g2(n)) alors
f1(n)*f2(n) O(g1(n) * g2(n))
Exemple: (3n2 +3)(n2+5nlog n) O(n4)
Règles de simplification
Si p(n) est un polynôme de degré k
alors p(n) (nk)
Règles de simplification
logk (n) O(n)
pour toute constante k>0
logk(n) = O(n)
logk(n) cn
≤ 1
lim n→∞
logk(n) cn
= lim n→∞
k(k − 1)logk−2(n)
k logk−1(n) cn
lim n→∞
= cn
=
(règle de l’Hôpital) ...
=lim n→∞
k! cn = 0
Exemples
Exemple 1: a = b;
Temps constant: (1).
Exemple 2:
somme = 0;for (i=1; i<=n; i++) somme += n;
Temps: (n)
Exemples
Exemple 3:
somme = 0;for (i=1; i<=n; i++) for (j=1; j<=i; j++) somme++;
Temps: (1) + O(n2) = O(n2)
On peut montrer : (n2)
Exemples
Exemple 4:
somme = 0;for (j=1; j<=n; j++) for (i=1; i<=n; i++) somme++;for (k=0; k<n; k++) A[k] = k;
Temps: (1) + (n2) + (n) = (n2)
Exemples
Exemple 5:
somme = 0;for (k=1; k<=n; k*=2) for (j=1; j<=n; j++) somme++;
Temps: (nlog n)
Exemples
lSum = 0;
for( int i = 0; i < n; ++i )
lSum++;
lSum = 0;
for( int i = 0; i < n; ++i )
for( int j = 0; j < n; ++j)
lSum++;
Exemples
lSum = 0;
for( int i = 0; i < n; ++i ) lSum++;
for( int j = 0; j < n; ++j) lSum++;
lSum = 0;
for( int i = 0; i < n; ++i )
for( int j = 0; j < n*n; ++j)
lSum++;
Exemples
lSum = 0;
for( int i = 0; i < n; ++i )
for( int j = 0; j < i; ++j)
lSum++;
lSum = 0;
for( int i = 0; i < n; ++i )
for( int j = 0; j < n*n; ++j)
for( int k = 0; k < j; ++k)
lSum++;
Exemples
lSum = 0;
for( int i = 1; i <= n; ++i )
for( int j = 1; j < i*i; ++j)
if( j % i == 0) for( int k = 0; k < j; ++k)
lSum++;
Analyse de problèmes
Borne supérieure: Borne supérieur sur le meilleur algorithme connu.
Borne inférieure: Borne inférieure sur tous les algorithmes possibles.
Exemple: Trier un tableau de taille n nécessite O(n) étapes et peut se faire en O(nlog n) étapes.
Temps de calcul
Exemple
T(n) = O(n4).
De combien le temps de calcul augmente-t-il
si n est multiplié par 10 ?
T(n) = O(n4) = cn4
T(10n) = c(10n)4 = 104 cn4 = 10 000 T(n)
Logarithmes
logb(n) = k ⇔ bk = n
logb(n) = loga(n) / loga(b)
logb(n) = O(log(n)) (la base ne compte pas)
Le log apparaît lorsque systématiquement, on découpe le problème en deux morceaux de même taille
Logarithmes et exposants
log(xy) = log(x) + log(y)
log(xa) = alog(x)
a(b+c) = abac
abc = (ab)c
Temps de calcul
Exemple
T(n) = O(n logn).
De combien le temps de calcul augmente-t-il si n est multiplié par 10 ?
T(n) = cn log(n)
T(10n) = c(10n) log(10n)
T(10n) = 10cn log(n) + 10cn log(10)
T(10n) = 10T(n) + dn
Recherche binaire
point milieu données initialement triées
Analyse par télescopage
T(n) = T(n/2) + O(1)
T(n/2) = T(n/4) + O(1)
T(n/4) = T(n/8) + O(1)
…. = ….
T(2) = T(1) + O(1)
Analyse par télescopage
T(n) = T(n/2) + O(1)
T(n/2) = T(n/4) + O(1)
T(n/4) = T(n/8) + O(1)
…. = ….
T(2) = T(1) + O(1)
Analyse par télescopage
T(n) = T(n/2) + O(1)
T(n/2) = T(n/4) + O(1)
T(n/4) = T(n/8) + O(1)
…. = ….
T(2) = T(1) + O(1)
Analyse par télescopage
T(n) = T(n/2) + O(1)
T(n/2) = T(n/4) + O(1)
T(n/4) = T(n/8) + O(1)
…. = ….
T(2) = T(1) + O(1)
Analyse par télescopage
T(n) = T(n/2) + O(1)
T(n/2) = T(n/4) + O(1)
T(n/4) = T(n/8) + O(1)
…. = ….
T(2) = T(1) + O(1)
Analyse par télescopage
T(n) = T(n/2) + O(1)
T(n/2) = T(n/4) + O(1)
T(n/4) = T(n/8) + O(1)
…. = ….
T(2) = T(1) + O(1)
⇒ T (n)= T (1) + O(1) = O(log n) i=1
log n
Temps de calcul
Exemple
T(n) = O( log n).
De combien le temps de calcul augmente-t-il si n est multiplié par 1000 ?
T(n) = c log(n)
T(1000n) = c log(1000n)
T(1000n) = c log(n) + c log(1000)
T(1000n) = T(n) + 10c
Code source
template <typename Comparable>
int binarySearch( const vector<Comparable> & a, const Comparable & x )
{
int low = 0;
int high = a.size( ) - 1;
int mid;
while( low < high )
{
mid = ( low + high ) / 2;
if( a[ mid ] < x ) low = mid + 1;
else high = mid;
}
return ( low == high && a[ low ] == x ) ? low : NOT_FOUND;
}
Limitation de l’analyse
Si on pense que T(n) = Θ (f(n)), on peut valider expérimentalement T(n)/f(n) = c
Considérez des n suffisamment grands
Lors de l’analyse, on choisit souvent le pire des cas, mais celui-ci peut être significativement pire que le cas moyen !
Limitation de l’analyse
T(n)/f(n)
Espace mémoire
La quantité d’espace mémoire utilisé peut aussi être étudiée à l’aide de l’analyse asymptotique.
En général:Temps: Algorithme manipulant les
structures de données.
Espace: Structure de données
Compromis espace/temps
Il est souvent possible de réduire le temps d’exécution au prix d’augmenter l’espace mémoire et vice versa.
Fichiers compressésTable des valeurs d’une fonctionsInsérer un nœud dans une liste chaînée
Espace disque: Un programme sera d’autant plus rapide qu’il requiert peu d’accès disque.