Règles de calcul
On va donner ici quelques règles de calcul de complexité pour que vous puissiez estimer rapidement la complexité d'un algorithme simple.
Une boucle simple
Lorsque l'on a une boucle où le nombre de fois où l'on va rentrer dedans est évident.
Par exemple :
tant que condition:
bloc d'instructions
Complexité d'une boucle tant que
Souvent,
pour chaque élément de structure:
bloc d'instructions
Complexité d'une boucle pour chaque
Si le bloc d'instructions est une suite d'instructions de complexité
Exemple :
total ← 0
pour chaque i de [1, n - 1]:
total ← total + 1
rendre total
La ligne 3 étant de complexité
À retenir
Si le bloc d'instruction est une suite d'instructions de complexité
Boucles imbriquées indépendantes
Plusieurs boucles imbriquées dont dont le nombre de fois où l'on va rentrer dedans est indépendant des autres boucles. Par exemple :
boucle 1 exécutée n1 fois:
boucle 2 exécutée n2 fois:
...
boucle i exécutée ni fois:
bloc d'instructions
On peut utiliser la règle précédente de façon récursive, la partie
Complexité de boucles imbriquées indépendantes
La complexité des boucles imbriquées est le produit du nombre de fois où l'on rentre dans chaque boucle pris indépendamment multiplié par la complexité du bloc d'instructions.
Exemple :
total ← 0
pour chaque i de [1, n - 1]:
pour chaque j de [1, n]:
total ← total + 1
rendre total
La boucle en
À retenir
Compter le nombre d'itération d'une boucle avec les
Boucles dépendantes mais monotones
Il arrive souvent que les boucles imbriquées d'un algorithme soient dépendantes les unes des autres. Dans le cas général on ne peut pas factoriser le calcul de la complexité et il faut alors dérouler tout l'algorithme en additionnant les complexités de chaque ligne comme s'il n'y avait pas de boucles.
Il existe cependant un cas pratique (et qui arrive assez souvent) où l'on peut factoriser :
Complexité de boucles dépendantes monotones
Si une boucle s'exécute un nombre variable de fois, mais que cette variation est croissante (respectivement décroissante), on peut considérer pour le calcul de la complexité qu'elle s'exécute à chaque fois de l'ordre du maximum de fois et se ramener au cas des boucles indépendantes.
On va vérifier cela avec un exemple :
total ← 0
pour chaque i de [1, n-1]:
pour chaque j de [i+1, n]:
total ← total + 1
Rendre total
Le nombre de fois où la boucle en
Refaisons le calcul en décomposant toutes les instructions, comme on le ferait dans le cas général, pour voir que notre règle est valide (et donnera aussi une idée de la preuve de cette règle) :
- ligne 1 :
- itération pour
:- ligne 2 : une affectation
: - boucle pour
:- ligne 3 : une affectation de
: - ligne 4 :
- le tout
fois
- ligne 3 : une affectation de
- ligne 2 : une affectation
- itération pour
:- ligne 2 : une affectation
: - boucle pour
:- ligne 3 : une affectation de
: - ligne 4 :
- le tout
fois
- ligne 3 : une affectation de
- ligne 2 : une affectation
- ...
- itération pour
:- ligne 2 : une affectation
: - boucle pour
:- ligne 3 : une affectation de
: - ligne 4 :
- le tout
fois
- ligne 3 : une affectation de
- ligne 2 : une affectation
- ligne 5 :
Notre complexité totale est donc :
Comme
Ce qui donne :
et donc notre complexité vaut :
Comme la somme des n premiers entiers vaut
Ce qui est de l'ordre de :
On retrouve bien le résultat attendu.
Complexité d'algorithmes récursifs
Un algorithme récursif est un algorithme qui s'appelle lui-même jusqu'à ce qu'on arrive à une condition d'arrêt qui stope la récursion. On en calcule la complexité en posant une équation qu'il faut résoudre :
À retenir
Pour calculer la complexité d'un algorithme récursif en fonction de la taille
Pour illustrer ce calcul, reprenons l'exemple du calcul du maximum :
algorithme maximum_rec(t: [réel], n: entier) → entier:
si n == 0:
rendre 0
sinon:
x ← maximum_rec(t, n-1)
si t[x] > t[n]:
rendre x
sinon:
rendre n
On exécute cette fonction avec comme paramètres initiaux un tableau nommé t
de taille n = t.longueur - 1
. On sait que cet algorithme fonctionne (on l'a déjà prouvé). Le calcul de la complexité se fait en résolvant une équation de récurrence. On pose que la complexité de notre algorithme pour un tableau de taille
- définition d'une fonction
- une comparaison entre une constante et une variable :
- retour de fonction d'un élément d'un tableau :
- —
- une affectation, plus l'appel à la fonction avec un tableau de taille
(sa complexité est donc de par définition) : - un test d'un élément dans un tableau et d'une variable :
- retour de fonction :
- —
- retour de fonction d'un élément d'un tableau :
Ce qui donne en sommant le tout :
La complexité est définie par l'équation de récurrence n
valant 1 et dans ce cas on a
Trouver
On a alors :
Au final, on trouve que la complexité