Telecharger ce cours (64.75 ko)

publicité
Algorithmique et complexité de calcul
Objectifs :
• Étude des techniques de conception et d'analyse des algorithmes.
• comparaison et classification des algorithmes.
• Ce n’est pas un catalogue d'algorithmes pour la résolution de
problèmes spécifiques.
Plan :
I
II
III
IV
V
VI
VII
VIII
Préliminaires
Analyse de l'efficacité des algorithmes
Diviser pour régner
Algorithmes voraces
Programmation dynamique
Transformation du domaine
Algorithmes probabilistes
Pré conditionnement
Chapitre 1 : Préliminaires
1 Notion d’algorithme
2 Efficacité des algorithmes
3 Nature de l’analyse
4 Pourquoi des algorithmes efficaces
5 Calcul des nombres de Fibonacci
1 Notion d’algorithme
Origine : le mot "algorithme" est associé au célèbre auteur Perse
Abou Jaafar Mohammed Ibn Moussa Al Khawarizmi connu pour son
livre "Al Jabr oua El Mokabala" écrit en l'an 825.
Un algorithme est une méthode systématique pour résoudre un
problème donné. L'exécution ne doit pas laisser la place à
l'interprétation, l’intuition ni à la créativité.
L’Algorithmique est l’étude des techniques de conception et
d’analyse des algorithmes.
Intérêt de l’étude de l’efficacité d’un algorithme ou de sa
complexité :
Un problème peut être résolu par plusieurs algorithmes.
L’étude de la complexité permet de choisir le meilleur = le plus
efficace. L’efficacité est caractérisée par :
Les temps d’exécution (on recherchera le plus rapide)
L’occupation de la mémoire
Consommation optimale des ressources de l’ordinateur
Cette étude utilise
 La trace
 Chronomètre
 Etude théorique
Exemples :
• Multiplication des nombres entiers
• Tri
• Fibonacci
Multiplication des nombres : 8*9 et 54*17
Travail : Proposer des algorithmes pour faire ces multiplications et
des outils pour les comparer.
Algorithmes classique et russe
Pré requis pour les multiplications:
Méthode classique : tables de multiplication et d’addition
Méthode russe : multiplication par 2 et division par 2 (décalages
à droite et à gauche dans une représentation en base 2) +
addition
Travail demandé :
Compter le nombre de divisions et opérations
Ecrire l’opérande qui est divisé en binaire
Conclusion ?
Algorithme de multiplication russe
fonction russe (a,b)
tableau X , Y
X[1]  a , Y[1] b, i 1 { initialisation }
tant que X[i] > 1 faire {former les 2 colonnes}
X[i + 1] X[i] div 2
Y[i + 1] Y[i] * 2
ii+1
p 0 {addition des entrées appropriées}
tant que i > 0 faire
si (X[i] mod 2 = 1) alors p  p + Y[i]
i i-1
retourner p
Exercice : Faire la trace pour l'exemplaire (17,53). Modifier cet
algorithme pour avoir une seule boucle et utiliser des variables
scalaires.
Autre algorithme de multiplication russe
fonction autre_russe (a , b)
entier x , y
x a, y  b, p  0 {initialisation}
tant que x ≥ 1 faire
si (x mod 2 = 1) alors p  p + y {ajouter la valeur
appropriée}
x  x div 2
yy*2
retourner p
Algorithme de la multiplication pas russe
fonction pas_russe (A,B)
tableau X,Y
X[1]  A, Y[1]  B, i  1 { initialisation }
tant que X[i] > 1 faire { former les 2 colonnes }
X[i + 1]  X[i] - 1
Y[i + 1]  B
i i+1
P  0 { additionner les entrées appropriées }
tant que i > 0 faire
si X[i] > 0 alors P  P + Y[i]
i i-1
retourner P
2 Efficacité des algorithmes
Définition : Un exemplaire x est l’entrée d’un algorithme, |x| = n =
taille de l'exemplaire x
Exemples :
- Tri : |x| est le nombre d'entiers à ordonner.
- Multiplication : |x| est le nombre de chiffres (ou bits) des facteurs
Approches d’analyse :
- Empirique : programmation + exécution avec plusieurs exemplaires
- Théorique : déterminer la quantité de ressources (temps,
mémoire,...) en fonction de la taille des exemplaires
Avantages de l'approche théorique :
- Indépendance de l'ordinateur et langage de programmation
- Gain dans l'exécution des algorithmes inefficaces
- Taille des exemplaires n'est pas une contrainte
3 Nature de l’analyse
Efficacité d’un algorithme dépend
- taille de l’exemplaire
- espace mémoire
-…
Comparaison des algorithmes selon différentes analyses
- meilleur cas (optimiste)
- moyenne
- pire cas (pessimiste)
Cf. Notebook pour Tri et Fibonacci
Tri par insertion
Procédure insert (T[1..n])
pour i2 jusqu'à n faire
xT[i]
j i - 1
tant que j > 0 et T[j] > x faire
T[j + 1] T[j]
j j - 1
T[j + 1]  x
Exercice : Faire la trace pour
T = [3,1,4,0,5], U = [0,3,4,6,9] et V = [9,6,4,3,0]
Et W = [7,4,3,1],
Tri par sélection
Procédure select (T[1..n])
pour i1 jusqu'à n-1 faire
minj i, minxT[i]
pour j i + 1 jusqu'à n faire
si T[j] < minx alors
minjj
minxT[j]
T[minj] T[i]
T[i]  minx
Exercice : Faire la trace pour W = [7,4,3,1],
Travail demandé :
 Programmer ces algorithmes avec des chronos en
déduire le plus rapide
 Faire la trace en déduire la fonction de récurrence qui
donne le temps d’exécution en fonction de la taille
 Classer ces temps d’exécution du + rapide au plus lent
Question : Faut-il concevoir des algorithmes performants ou des
machines de plus en plus puissantes ?
Supposons :
Un algorithme A et une machine M
Un algorithme A’ plus efficace que A
Une machine M’ plus puissante que M
t(n) = temps d’exécution, sur un exemplaire de taille n, de A sur M
t’(n): temps d’exécution dans un ordinateur plus rapide, de A sur M’
t’’(n): temps d’exécution d’un algorithme plus efficace : de A’ sur M
t(n)= 10-4 x 2ns
t’(n)= 10-2 x 10-4 x 2n = 10-6 x 2n s
t’’(n)= 10-4 x n3 x 102 = 10-2 x n3 s
Relevé des temps d’exécution
n
t(n)
t’(n)
t’’(n)
10
1/1O s
2 ms
10 s
20
2 mn
1s
1 mn
30
10 jours
3 heures
5 mn
38
1 année
4 mois
10 mn
45
-
1 année
20 mn
200
-
-
1 jour
1500
-
-
1 année
Graphes des temps d’exécution en log, log
L’amélioration des algorithmes est plus intéressante que celles des machines
Voilà pourquoi il faut des algorithmes efficaces
Définition de ‘’Ordre de f(n)‘’ = (majoration)
Soit f : IN  IR*
O( f(n) ) = { t : IN  IR+ / (  c  IR+ )(  n0  IN )  n  n0 t(n)  c f(n) }
O ( f(n) ) est appelé l’ordre de f(n).
t(n) est dans l’ordre de f(n) ssi t(n)  O ( f(n) )
Travail demandé :
a) Quel est l’ordre d’un algorithme dont le temps d’exécution vérifie la
récurrence suivante:
T (n) = 27 n2 ms - 18 n ms + 3 s
b) Prouver que: si f(n)  O ( g(n) ) et g(n)  O ( h(n) ) alors f(n)  O ( h(n) )
c) Déduire alors que si g(n)  O ( h(n) ) alors O ( g(n) )  O ( h(n) )
d) Soient f et g : IN  IR+, montrez que : O ( f(n) + g(n) ) = O (max(f(n),g(n) )
e) Soient f et g : IN  IR+, et c prouvez que :
 lim n  f(n) / g(n) = c  IR+  O ( f(n) ) = O ( g(n) )
 lim n  f(n) / g(n) = 0  O ( f(n) )  O ( g(n) )
f) Prouver que: log n  O ( n )
et
n  O (log n)
g) Soit 0< x <1 , utilisez  pour classer les ordres des fonctions suivantes :
nLog n, 1, n , Log n , n , n2 , n2 / Log n , n (1+x) , (1+x) n , n8
Définition de ‘’Oméga de f(n)‘’ = (minoration)
W( f(n) ) = { t : IN  IR+ / (  c  IR+ )(  n0  IN )  n  n0 t(n)  c f(n) }
Définition de ‘’Ordre exacte de f(n)‘’ : Q ( f(n) )
Q ( f(n) ) = O (f(n))  W (g(n))
Ou encore t(n) est borné par : c1 f(n)  t(n)  c2 f(n)
Travail demandé :
 Programmer ces 3 algorithmes avec des chronos, remplir
alors le tableau et en déduire le plus rapide
Suites de Fibonacci
 Faire la trace de fib1, fib2 et fib3 pour n = 5
 Déterminez la classe (complexité) du temps d’exécution
pour chaque algorithme
 Exécutez (Dev) en ayant implémenté des compteurs pour
les 3 algorithmes pour les valeurs de n proposées et
présentez les temps d’exécution dans le tableau suivant :
 Conclusions
n
10
20
30
40
50
102
104
106
XXX
XXX
XXX
fib3
fib2
fib1
fonction fib1(n)
si n < 2 alors retourner n
sinon retourner fib1(n-1) + fib1(n-2)
fonction fib2 (n)
j  0 ; i1
pour k1 jusqu'à n faire
ji + j
i j - i
retourner j
fonction fib3(n)
i  1 ; j 0 ; k  0 ; h  1
tant que n > 0 faire
si n est impair alors
t  jh
j  ih + jk + t
i  ik + t
t  h2
h  2kh + t
k  k2 + t
n  n div 2
retourner j
Téléchargement