Complexité Algorithmique : Temps et Mémoire
Complexité Algorithmique : Temps et Mémoire
On considère que toutes ces opérations élémentaires ont le même coût qui égale à 1, indépendamment des données d’entrée.
Ainsi, si on considère deux blocs d’instructions P et Q avec CP est le cout du bloc P et CQ est le cout du bloc Q, alors le cout
total est CP + CQ
Exemple :
Algorithme Complexité
S=1 # instruction 1
S=S*n # instruction 2 CA = C instruction 1 + C instruction 2 + C instruction 3 = 1 + 2 + 2 = 5
S=S-n # instruction 3
Najlàa ESSALHI 2021-2022 CPGE Mohamed V-Casablanca
Si le cout de Q1 est CQ1 et celui de Q2 est CQ2, alors on a: C ≤ C test + max (CQ1, CQ2)
Exemple :
Algorithme Complexité
if i % 2= = 0 : #test
n = i // 2 #bloc 1
else : CB ≤ C test + max (C bloc 1, C bloc 2) ≤ 2 + max (2,4) ≤ 6
i = i+1 #bloc 2
n = i // 2
Exemple 1 :
Algorithme Complexité
S=0
3 3
for i in range(n+1) :
S=S+i 𝐶(𝑛) = 1 + 𝐶1&12% = 1 + 2 = 1 + 2 𝑛 + 1 = 2𝑛 + 3
%&4 %&4
Exemple 2 :
Algorithme Complexité
for i in range(n):
for j in range(i): >@' :@' >@' :@' >@'
n(n − 1)
S=i+j C(n) = C 9&:2; + C<=:>? 9 = 3= 3i = 3
2
print(S) :&4 ;&4 :&4 ;&4 :&4
Exemple 3 :
Algorithme Complexité
Remarque :
Généralement, on s’intéresse à la complexité dans le pire des cas, car cela correspond à la performance de l’algorithme
lorsqu’il prend le plus de temps.
Exemple : recherche d’un élément X dans un tableau
def recherche(X,T) :
for i in range(len(T)) :
if X==T[i] :
return True
return False
𝐂 𝐧 = 𝟏+𝟏 • Donc :
C(n) = 2 𝐢&𝟎
Najlàa ESSALHI 2021-2022 CPGE Mohamed V-Casablanca
𝐧
=𝐧+ 𝟏 𝐪 𝐪𝐧 𝐧+𝟏 𝐧+𝟏
𝐂 𝐧 = 𝐢 + 𝐧 𝟏−𝐪 = +𝐧 𝟏−𝐪 =𝐪 +𝐧 𝟏−𝐪
𝐧 𝐧 𝟐 𝟐
𝐢&𝟏
Remarque :
• Si f=O(g) et g=O(h) alors f=O(h)
• Si f=O(g) et k une constante alors k*f=O(g)
• Si f1=O (g1) et f2=O (g2) alors : f1+f2= O (g1+g2) et f1*f2= O (g1*g2)
Règles de simplification :
• Un nombre constant d’instructions est négligeable par rapport à la croissance de la taille des données, ce qui permet
d’annuler les constantes additives.
• Pour de grandes valeurs de n, c’est bien sûr le terme de plus haut degré qui est dominant
• Les processeurs actuels effectuent plusieurs millions d’opérations par seconde, on remplace donc les constantes
multiplicatives par des 1
Exemples :
• f (n) = n3 + 2n2 + 4n + 2 = O(n3) (si n ≥1 alors f (n) ≤ 8n3)
• f (n) = n log(n) + 12n + 888 = O(n log(n))
[\
• f (n) = 1000n10 − n7 + 12n4 + = O(2n)
'444
Remarque : La complexité d’une instruction élémentaire est un O(1) : on dit qu’elle s’effectue en temps constant
2. Classes de complexité les plus usuelles :
Les algorithmes se regroupent en plusieurs familles, selon leurs complexités :
temps constant O(1) quelque soit la taille de l’entrée, le nombre d’opérations effectuées est constant.
temps sous linéaire O(log(n)) Le temps présente une dépendance logarithmique par rapport à la taille de l’entrée.
temps quadratique O(n2) quand la taille de l’entrée double, le temps d'exécution est multiplié par 4
Najlàa ESSALHI 2021-2022 CPGE Mohamed V-Casablanca
temps polynomial O(nk) quand la taille de l’entrée double, le temps d'exécution est multiplié par 2k
temps exponentiel O(kn) quand la taille de l’entrée double, le temps d'exécution est élevé à la puissance 2
1. Exemples :
ü Exemple 1 : La fonction factorielle
n= len(T) • Dans le pire des cas le programme ne va pas trouver de doublons et retourne True, donc
for i in range (n-1) : il va comparer tous les éléments du tableau entre eux.
for j in range (i +1, n) : >@[ >@' >@[ >@'
n n−1
if (T [i] = = T [j]) : 3+ 1 =3+ n−1−i =3+ i=3+ = O(n[ )
2
:&4 ;&:2' :&4 :&'
return False
return True • Dans le meilleur des cas les deux premiers éléments de T sont identiques (une seule
comparaison et un return) on aura donc une complexité constante O(1)
def ProduitMatriciel (A, B) : • En effectue 3 affectations et 3 appels à la fonction « len » donc: cout= 6
n=len(A)
• Pour initialiser la matrice « prod », en effectue n multiplications et une
m= len(B[0])
p= len(B) affectation ce qui donne un cout= n+1
prod = [[0]*m for i in range(n) ] • Pour calculer une valeur de s : 3 opérations élémentaire (affectation, addition,
for i in range(n) : multiplication)
>@' y@' <@' >@' y@'
for j in range(m) :
s=0 C n =6+n+1+ 2+ 3 +1=8+n+ 2 + 3p
:&4 ;&4 k&4 :&4 ;&4
for k in range(p) :
s= s + A[i][k] * B[k][j] = 8 + n + n. m. 2 + 3p = 8 + n + 2n. m + 3p. n. m
= O(p. n. m)
prod[i][j]=s
• Si les matrice A et B sont des matrices carrées alors n=m=p ce qui donne une
return prod
complexité en O (n3)
Complexité :
Si n>2, on effectue une comparaison et une addition entre deux appels récursifs. Si n=0 ou n=1, seule la comparaison a lieu.
On a ainsi :
C(n) = C(n − 1) + C(n − 2) + 2 (1)
C(0) = C(1) = 1
La complexité est donc une suite récurrente linéaire non homogène d'ordre deux. Cette récurrence est aussi vraie pour n+1 :
C n+1 = C n + C n−1 + 2 (2)
En soustrayant (1) de (2), on obtient l’équation suivante :
C(n + 1) − 2C(n) + C(n − 2) = 0
Cette nouvelle équation est une équation homogène dont l'équation caractéristique est :
X• − 2 X[ + 1 = X − 1 X[ − X − 1 = 0
et dont les racines sont :
' 2 ‚ ' @ ‚
X1 = et X2 = et X3=1
[ [
Donc :
> > >
1+ 5 1– 5 1 + 5
∃µ, λ, γ ∈ ℝ, C(n) = λ +µ +γ=O
2 2 2
Najlàa ESSALHI 2021-2022 CPGE Mohamed V-Casablanca
On détermine alors λ, µ et 𝛾 en se servant de la valeur des trois premiers termes C(0) = 1 et C(1) = 1 et C(2) = 4
La complexité de cet algorithme est donc exponentielle
2. Suites non-linéaires de type "diviser pour régner":
a. Principe:
La méthode de diviser pour régner est une méthode qui permet, parfois de trouver des solutions efficaces à des problèmes
algorithmiques. Elle se fait en trois étapes :
ü Diviser : on divise les données initiales en plusieurs sous-parties.
ü Régner : on résout récursivement chacun des sous problèmes associés (ou on les résout directement si leur taille est assez
petite).
ü Combiner : combiner les différents résultats obtenus pour obtenir une solution au problème initial.
Avec ce paradigme, la complexité d’un algorithme traitant des données de taille n s’écrit souvent :
>
C n =a C + f n et C n4 = c
}
Complexité :
def dicho(l, x, d, f):
if d > f: On a :
return False 3
T(n) = O(1) + T ( ) et T(0) = O(1)
[
else:
m = (d + f) // 2 On a : a=1 et b=2, f(n)=O(1) donc k = 0 et a = bk = 1
if l[m] = = x: D’où d’après le théorème général :
return True
T(n) = O (𝑙𝑜𝑔[ (𝑛))
else:
if x < l[m]:
return dicho(l,x,d,m-1)
else:
return dicho(l,x,m+1,f)
Najlàa ESSALHI 2021-2022 CPGE Mohamed V-Casablanca
On a :
T(n) = T (n − 1) + 2 pour n > 1
T(0) = 1 T(1) = 1
En substituant à chaque fois dans la récurrence on obtient :
T(n) = T (n − 1) + 2 = [T (n − 2) + 2] + 2 (j’ai « +2 » 2 fois)
= [[T (n − 3) + 2] + 2] + 2 (j’ai « +2 » 3 fois)
= …………
= T (n-k) + 2 + ... + 2 + 2 + 2 (j’ai « +2 » k fois)
= …………
= T(1) + 2 + ... + 2 + 2 + 2 (j’ai « +2 » n-1 fois)
3@'
= 1+ %&' 2 = 1+ 2 (n-1) = O (n)
ü Exemple 2 :
On a :
T(n) = T (n − 1) + n, pour n > 1
T(1) = 1
T(n) = T (n − 1) + n = [T(n − 2) + (n − 1)] + n
= [[T (n − 3) + (n − 2)] + (n − 1)] + n
= …………………
= T(1) + 2 + ... + (n − 2) + (n − 1) + n
= 1+2+ ... + (n − 2) + (n − 1) + n
3 3(3 2 ')
= %&' 𝑖 = = O (n2)
[
ü Exemple 3 :
Soit :
3
T(n) = n + 2 T ( ) et T(1) = 1
[
3 3 3
Donc T ( ) = + 2 T ( )
[ [ [“
On substituant d’une façon répétitive jusqu'à arriver au cas de base T(1), c'est-à-dire à une étape k qui vérifie
3
= 1 donc à l’étape k= log [ (𝑛):
[p
3
T(n) =n+2T( )
[
Najlàa ESSALHI 2021-2022 CPGE Mohamed V-Casablanca
3 3 3
= n+ 2 ( + 2 T ( )) = 2 n + 2[ T ( )
[ [“ [“
3 3 3
= 2 n + 2[ ( +2T( )) = 3 n + 2• T ( )
[“ [” [”
= ……………….
3 3 3
= (i-1) n + 2(%@') ( +2T( )) = i n + 2% T ( )
[(•mn) [• [•
= ……………….
3 3 3
= (k-1) n + 2(t@') ( +2T( )) = k n + 2t T ( )
[(pmn) [p [p
On a donc :
n n
C(n) = 1 + C ( ) = 1 + log [ + 1 = 2 + log [ (n) − log [ 2 = 1 + log [ (n)
2 2
• Il reste à vérifier le cas de base : C 1 = 1 = 1 + log [ (1)
Donc pour toute n ≥ 1 on a: C n = 1 + log [ n = O (log [ (n))