Algorithmie PC 1 : Complexité corrigé 1Élements de complexité

publicité
Algorithmie
PC 1 : Complexité
corrigé
1
Élements de complexité
1.1
Définitions
Le nombre d’opérations effectués ou la place mémoire prise par un programme
est souvent notée en O(). Une définition mathématique de cette fonction peut
être :
Une fonction g(N) est en O(f (N )) (de l’ordre de f(N)) s’il existe deux constantes c0 et N0 tels que g(N ) < c0 f (N ), pour tout N > N0 .
1.2
Jeux des différences
1.2.1
Quelle est la différence entre O(1) et O(2) ?
en notant f(N)=1 et g(N)=2 on a que pour tout N, f(N) < g(N) et g(N) <
3f(N). Ces deux fonctions sont donc équivalentes.
On peut donner les règles suivantes :
• O(f (N ) + g(N )) = O(f (N )) + O(g(N ))
• O(A ∗ f (N )) = A ∗ O(f (N )) = O(f (N ))
• f (N ) ∗ O(g(N )) = O(f (N ) ∗ g(N ))
1.2.2
Quelle est la différence entre O(N 2 + N 3 ) et O(N 3 ) ?
De même que précédemment ces deux fonctions sont équivalentes. On a
O(N 2 + N 3 ) = O(N 2 ) + O(N 3 ). Comme N 2 est en O(N 3 ), O(N 2 ) + O(N 3 ) =
O(N 3 ) + O(N 3 ) = 2O(N 3 ) = O(N 3 )
1
1.3
Calcul de complexité pour des algorithmes fictifs
1.3.1
Donnez une complexité de l’algorithme suivant (et dites ce qu’il fait)
En dehors des boucles, il n’y a qu’une unique affectation. Il y a deux boucles imAlgorithme 1 Algorithme ne servant pas à grand chose
Données
n
Début
total=0
de i=1 a n-1 faire
de j=i+1 a n faire
total=total+1
Rendre k
Fin
briqués, et à l’intérieur des deux boucles une affectation, donc en O(1). Chaque
boucle étant en O(n), la complexité de cet algorithme est en O(n2 ). On peut
bien sur regarder toutes les opérations une à une et on trouverait un nombre
d’opération égal à 1 + n(n-1)/2.
L’algorithme fait de nombreuses choses : il compte les boucles, calcule le
nombre de sous-ensembles à 2 éléments d’un ensemble à n éléments, etc...
1.3.2
Quel est la complexité d’un algorithme qui, à partir de n données
initiales, examine toutes les données, en supprime une et recommence
(examen des données et suppression) jusqu’à ce qu’il n’y ai plus de
données.
On peut utiliser la formule de récurrence C(N ) = N + C(N − 1), où C(N)
est la complexité de l’algorithme à N données.
On a alors C(N ) = N + N − 1 + N − 2 + ... + 1 = N (N + 1)/2
2
2.1
Récursion
Définition
La récursion est un principe fondamental en mathématique (la preuve par
récurrence par exemple) et en informatique. Une définition simple de ce principe
en informatique est qu’un programme récursif s’appelle lui-même.
Pour éviter que le programme ne s’appelle indéfiniment, il est nécessaire
d’avoir une condition d’arrêt, qui, lorsqu’elle est satisfaite empêche le programme de s’appeler lui-même.
2
2.2
Factorielle
La définition mathématique de la fonction factorielle est pour tout entier N :
˙ − 1)! pour N ≥ 1
N ! = N (N
0! = 1
Voici une version algorithmique de l’équation :
Algorithme 2 Algorithme Factorielle(N)
Données
N
Début
Si N = 0 Alors
Rendre 1
Sinon
Rendre N*Factorielle(N-1)
Fin
2.2.1
L’algorithme 2 calcule-t-il bien une factorielle ?
Ben oui, il calcule bien ce qu’il faut. On le prouve par récurrence. Pour
n = 0 on a bien que Factorielle(0) = 1 = 1!. On suppose donc que pour n ≥ 0,
Factorielle(n) = n!.
Pour n + 1. L’algorithme retourne (n + 1) ∗ F actorielle(n). Par hypothèse
de récurrence Factorielle(n) = n!, donc Factorielle(n+1) =(n+1)*Factorielle(n)
= (n+1)*n! = (n+1)!.
2.2.2
Quel est le domaine de définition l’entier N de l’algorithme 2 ? Que
se passe-t-il si N est en dehors de son domaine ?
Le domaine de définition est l’ensemble des entiers naturels. Si N est un réel
ou un entier négatif, l’algorithme ne s’arrête pas. Pour pallier ce problème on
peut changer le test si N=0 alors rendre 1 par si N ≤ 0 alors rendre 1
2.2.3
Quelle est la complexité de l’algorithme 2 ?
Encore une fois, on va calculer sa complexité par récurrence. Soit C(N) le
nombre d’opération effectué par l’algorithme 2. On a C(0) = 1, puisqu’il y a une
affectation (on ne compte pas le test comme une opération ici). De plus, C(N)
= 1 + C(N-1) pour N > 0 puisque l’on multiplie le résultat de Factorielle(N-1)
à N.
3
Ainsi, C(N) = 1 + C(N-1) = 1 + 1 + C(N-2) = .... = N + C(0) = N+1.
Le calcul de Factorielle avec l’algorithme 2 est donc en O(n).
2.3
Fibonacci
La définition mathématique de la suite de Fibonacci (destinée initialement à
compter le nombre de lapin génération après génération. Le problème initial,
proposé en 1202 était en effet : Partant d’un couple, combien de couples de
lapins obtiendrons-nous après un nombre donné de mois sachant que chaque
couple produit chaque mois un nouveau couple, lequel ne devient productif
qu’après deux mois.)
est pour tout entier N :
F (N ) = F (N − 1) + F (N − 2) pour N ≥ 2
F (0) = F (1) = 1
2.3.1
S’inspirer de l’algorithme 2 pour écrire un programme récursif calculant la suite de Fibonacci.
Algorithme 3 Algorithme Fibonacci(N)
Données
N
Début
Si N ≤ 1 Alors
Rendre 1
Sinon
Rendre Fibonacci(N-1) + Fibonacci(N-2)
Fin
2.3.2
Calculer le nombre d’appels au programme Fibonacci lors de l’exécution de
Fibonacci(n).
Lorsque N vaut 0 ou 1, le nombre d’appel est égal à 1. Pour N≥ 2, le nombre d’appel à Fibonacci est égal au nombre d’appels de Fibonacci(N-1) plus le
nombre d’appels de Fibonacci(N-2) plus 1. Le nombre d’appel à Fibonacci pour
l’algorithme 3 est donc égal à 2*Fibonacci(N)-1, et est donc en O(Fibonacci(N)).
Pour calculer le nombre d’appels précisément, on va trouver un équivalent à
Fibonacci(N).
La suite Fibonacci(N)/Fibonacci(N-1), si elle converge, converge vers Φ =
√
1+ 5
qui est la solution positive de l’équation x = 1 + 1/x. En effet, on a
2
Fibonacci(N)/Fibonacci(N-1) = 1 + Fibonacci(N-2)/Fibonacci(N-1) et donc si
4
la limite L existe elle satisfait L = 1 +1/L. Cette équation nous montre de plus
que pour tout N, Fibonacci(N)/Fibonacci(N-1) >1.
Il nous reste à montrer que Fibonacci(N)/Fibonacci(N-1) converge. En
posant f (x) = 1+1/x, on a que Fibonacci(N)/Fibonacci(N-1) -Φ = f(Fibonacci(N1)/Fibonacci(N-2)) -f(Φ). La formule des accroissements fini nous indique donc
qu’il existe c dans [min{Fibonacci(N-1)/Fibonacci(N-2), Φ}, max{Fibonacci(N1)/Fibonacci(N-2), Φ}] tel que :
f(Fibonacci(N-1)/Fibonacci(N-2)) -f(Φ) = f’(c)((Fibonacci(N-1)/Fibonacci(N2)-Φ).
Comme f 0 (x) = −1/x2 et que c > 1, on a que 0 < |f 0 (c)| < 1. Ainsi :
|Fibonacci(N)/Fibonacci(N-1) − Φ| ≤ A|(Fibonacci(N-1)/Fibonacci(N-2) − Φ)|,
avec A < 1. De là, |Fibonacci(N)/Fibonacci(N-1) − Φ| ≤ AN −2 |1 − Φ| et donc
Fibonacci(N)/Fibonacci(N-1) converge bien vers Φ.
Cette convergence nous permet ensuite de conclure que Fibonacci(N) est
équivalent à ΦN . Le nombre d’appel à Fibonacci est donc en O(Φn ).
2.4
Conclusion ?
Un nombre d’appel exponentiel, c’est trop ! L’algorithme proposé n’est
pas un bon algorithme pour calculer la suite de Fibonacci. La raison en est
que beaucoup beaucoup de choses sont calculées plusieurs fois. Par exemple
Fibonacci(N-2) est calculée pour Fibonacci(N) et pour Fibonacci(N-1).
Il faut trouver un moyen de ne calculer les choses qu’une et une seule fois.
2.5
Proposez un algorithme itératif calculant la suite de Fibonacci, et
donner en sa complexité.
La complexité est en O(N ). Ce qui n’a rien à voire avec O(Φn ).
3
Trop Poly pour être honnête
P
On représente un polynôme P (x) = a0 + 1≤i≤n ai xi de degré n par un tableau
tab de taille n + 1 tel que tab[i]=ai (0 ≤ i ≤ n).
3.1
Proposez un algorithme permettant de calculer la somme de deux
polynômes P (x) et Q(x) de même degré n. Quel est sa complexité ?
La complexité de cet algorithme est clairement en O(n).
3.2
Proposez un algorithme permettant de calculer le produit de deux
polynômes P (x) et Q(x) de même degré n. Quel est sa complexité ?
5
Algorithme 4 Algorithme Fibonacci(N)
Données
N
Début
Si N ≤ 1 Alors
Rendre 1
fib1 = 1
fib2 = 1
fib=0
de i=2 a i=n faire
fib=fib1+fib2
fib2 = fib1
fib1 = fib
Rendre fib
Fin
Algorithme 5 somme de deux polynômes
Données
n degré max des polynômes
P, Q les deux tableaux correspondant aux polynômes
Début
de i=0 a i=n faire
R[i] = P[i]+Q[i]
Rendre R
Fin
Algorithme 6 Produit de deux polynômes
Données
n degré max des polynômes
P, Q les deux tableaux correspondant aux polynômes
Début
de i=0 a i=2n faire
R[i] = 0
de i=0 a i=n faire
de j=0 a i=n faire
R[i+j] = R[i+j] + P[i]*Q[j]
Rendre R
Fin
6
La complexité est en O(n2 ). La première boucle est en effet en O(n) et
la double boucle en O(n2 ) puisque les opérations effectuées dans chacune des
boucles est en O(1).
3.3
Proposez un algorithme permettant de calculer la valeur d’un polynôme
P (x) de degré n pour une valeur x0 donnée. On pourra utiliser la fonction puissance(x,p) qui calcule la valeur de xp . Quel est la complexité
de cet algorithme ?
Algorithme 7 Évaluation d’un polynôme
Données
n degré max du polynôme
x valeur
P le tableau correspondant au polynôme
Début
eval = 0
de i=0 a i=n faire
eval = eval + P[i]*puissance(x,i)
Rendre eval
Fin
Òn suppose ici que puissance(x,0) = 1 quelque soit x. La complexité de cette
algorithme est lié à la complexité de puissance, qui effectue i multiplications pour
évaluer puissance(x,i). L’algorithme effectue ainsi de l’ordre de 1 + 2 + 3 + ... + n
opérations. Comme 1+2+3+...+n = n(n+1)/2, la complexité de l’algorithme
est O(n2 ).
3.4
Méthode de Horner
La méthode de Horner consiste à écrire un polynôme P (x) = a0 +
P
i
1≤i≤n ai x de la façon suivante : P (x) = a0 + x(a1 + ...x(an−1 + an x)...).
Ainsi, le polynôme P (x) = 1 + 2x − 6x2 + 3x3 + x4 s’écrira P (x) =
1 + x(2 + x(−6 + x(3 + x))). Cette utilisation finaude du parenthèsage
va nous permettre – pardon – vous permettre de créer un algorithme
d’évaluation d’un polynôme avec une complexité moindre que celui
de la partie 3.3.
Cet algorithme permet de ne pas recalculer les puissances de x à chaque fois.
De là, la complexité de l’algorithme devient O(n).
7
Algorithme 8 Évaluation d’un polynôme, le retour
Données
n degré max du polynôme
x valeur
P le tableau correspondant au polynôme
Début
eval = P[n]
de i=n a i=0 faire
eval = P[i]+ eval*x
Rendre eval
Fin
8
Téléchargement