|
• 2 cas typiques qui nécessitent des algorithmes efficaces :
– taille du problème énorme
– code exécuter un grand nombre de fois
• Recherche d'algorithme plus efficace et si possible simple
Analyse empirique d'un algorithme ?
Analyse mathématique d'un algorithme ?
• Ecriture en Java : mais peut-être implémenté dans n'importe quel autre langage
• Un algorithme fait parti d'un gros programme
– utilisation de structure de données abstraites
– peuvent être substituées
• Dès le début : connaître les performances d'un algorithme
• Tout le système en dépend (recherche, tri, …)
• Soit 2 algorithmes réalisant la même tâche– compare temps d'exécution sur des entrées typiques
– 3 s ou 30 s d'attente pour l'utilisateur feront une grande différence
– permet aussi de valider une analyse mathématique
• Si le temps d'exécution devient trop long, l'analyse mathématique s'impose
– attente pouvant être de l'ordre de l'heure ou du jour
|
• Nécessite l'implémentation d'une première version d'un algorithme !!!
• Nature des données à tester
– données typiques
– données aléatoires
– données extrêmes
• Attention à la comparaison– soin accordé à l'implémentation
– différences entre ordinateurs, compilateurs, systèmes
d'exploitation, ….
• Algorithme rapide souvent plus compliqué qu'un algorithme "brute force"
– problèmes de grande taille -> algorithme rapide
• Rien ne sert de multiplié par 10 la performance de l'algorithme si celui-ci – ne prend que quelques millisecondes
– et est très peu utilisé
• Le temps de développement peut-être prohibitif
• un programme non écrit ne peut-être testé!
|
• L'analyse mathématique d'un algorithme peut-être complexe
• Une spécialité en informatique
• Paramètres hors de portée du programmeur Java :
– temps d'exécution d'une instruction (MV/compilateur)
– ressources partagées
– dépendance des données en entrée
– certains algorithmes sont tout simplement complexes et il n'y a pas de résultat mathématique pour les décrire
• Néanmoins il est possible de prédire
– la performance d'un algorithme
– si un algorithme est meilleur qu'unautre
• Premières étapes:
– identifier les opérations abstraites de l'algorithmes
– exemple de la triple boucle, le nombre d'exécutions de l'instruction : count++
– sans tenir compte du temps en milliseconde
– cette séparation permet de comparer des algorithmes
|
• La plupart des algorithmes ont un paramètre N qui les caractérise :
– le nombre d'assurés sociaux
– le nombre de fichiers
– le nombre de caractères
• Une mesure abstraite du problème • Plusieurs paramètres peuvent exister :
– par exemple M et N (producteurs et consommateurs, usine de productions et sites de vente)
– garder un paramètre fixe en faisant varier l'autre paramètre
• But : exprimer les besoins en fonction de N ( ou M et N)
par des formules mathématiques
Type de fonctions
• 1 instructions exécutées un nombre limité de fois; exécution constante
• log N division du problème pour le résoudre; exécution logarithmique
• N exécution linéaire
• N*log Nrésolution de pbs plus petits, puis recombinaison des solutions
• N2 utilisable sur de petits pbs; exécution quadratique
• N3 triple boucle sur les données
• 2N exécution exponentielle; N=20 alors 2N=1 million
La notation O :
Soit deux fonctions f(x) et g(x) avec x ? 0 On dit que f(x)=O( g(x) ) si
? N0 ? 0, ? c ? 0, ? N ? N0 f (N) ? c . g (N)
A partir d'un certain rang, la fonction « g » majore la fonction « f » à un coefficient multiplicatif près.
On peut encore écrire : lim?? f (n) = c
n g(n)
• ? N0 ? 0, ? c ? 0, ? N ? N0 g (N) ? c . f (N)
• Cette notation permet de :
– limiter l'erreur quand on ignore les termes plus petits dans uneformule mathématique
– limiter l'erreur quand on ignore certaines parties du programme qui prennent peut de temps
– classer les algorithmes en fonction de leur comportement asymptotique (avec N grand)
• Les constantes N0 et c0 cachent des détails d'implémentation
• si N < N0 on ne connaît pas le comportement de l'algorithme
• On ne s’intéresse qu'aux termes les plus grands : comparer N2 nanosecondes et logN siècles
|
• f est O(g) est transitif : si f est O(g) et g est O(h) alors f est O(h)
• Le produit des bornes supérieures est la borne supérieure du produit : si f est O(g) et h est O(r) alors f*h est O(g*r)
• Les fonctions exponentielles croissent plus vite que les puissances : nk est O( bn ) ? b > 1 et k ? 0 ex : n20 est O( 1.05n)
• Les logarithmes croissent plus lentement que les puissances :
logbn est O( nk) ? b > 1 et k > 0 ex: log2n est O( n0.5)
Algorithmes polynomiaux et difficiles
• Algorithme polynomiale
– s'il est O(nd) pour un entier "d" donnée
• Ils peuvent être résolus en un temps raisonnable
• Algorithmes difficiles
– algorithmes pour lesquels il n'y a pas d'algorithme avec un temps polynomiale
Copyright " 'Algorithms in Java'; Robert Sedgewick & Michael Shildlowsky; Third edition, Parts 1-4; Addison-Wesley " Reproduction ULP Strasbourg. Autorisation CFC - Paris |
• T(0)=1
• T(1)=4
• T(N)=(N+1)2
• T(N) est O(N2) avec N0=1 et c=4
• T(N) ? 4*N2 pour N ? N0=1
• N0=0 n'est pas possible car T(0)=1 or c*02=0 pour toutes constantes c
• montrer que O(1) est la même chose que O(2) ?
? N0 ? 0, ? c ? 0, ? N ? N0 g(N) ? c . f (N)
• Cela revient à trouver 2 entiers N0 et c avec : f(N)=1 et la fonction g(N)=2
• N0 = 0 et c = 2 on a bien 2 ? c*1=2 pour tout ? ? N0 = 0
O(N) (4.2) ?ln N+?+ 1
• Avec la notation O(N) que devient cette estimation ?
a1 + 2a2N*HN + a3*N ns
• 2a2N*HN + O(N)
• Une forme plus simple qui indique que ce n'est pas la peine de chercher a1 et a3
• Temps d'exécution exprimé en notation « grand-O » ?
• HN=ln(N) + O(1) on obtient ainsi 2a2N*Ln(N)+ O(N)
• l'expression asymptotique du temps total d'exécution : temps proche de 2a2N*Ln(N) pour des N grands
|
• l'expression asymptotique du temps total d'exécution :
temps proche de 2a2N*Ln(N) pour des N grands
• que se passe-t-il si N double : taille 2N?
2a2(2N)ln(2N)+O(2N) = 2ln(2N)+O(1)
2a2N ln N+O(N) ln N+O(1)
= 2+O( 1 ) 2a2N en facteur ln N
• sans connaître a2 on peut prédire que le temps doublera pour le traitement des données de taille 2N
• Comment?
|
|
• Trier les nombres (N nombres) : O(NlogN) Coût faible comparé au nombre de comparaisons si on fait une recherche très souvent (M : nombre de recherche; M >>N)
• La recherche séquentielle : M*N
• La recherche binaire : NLogN + M*?
static int search(int a[], int v, int l, int r)
{ 2 situations : while(r>=l) {
if (v < a[m]) r=m-1; else l=m+1;
}
return -1;
} TN ? T?N/2? + 1, pour N ?2 avec T1 = 1
N=2n; TN ? n +1= ?lgN? + 1
N=109 recherche en au plus 30 comparaisons