Vous êtes sur la page 1sur 6

Mhamed AIT AAMMI HADI CPGE IBN GHAZI RABAT

Terminaison, correction et Complexité des algorithmes.


 Variant de boucle.
 Invariant de boucle.
 Complexité d’un algorithme

I. Introduction

Lorsqu’on veut utiliser une boucle dans un programme, on doit se poser les
questions ci-dessous :

 Quelle boucle utiliser :


 Les instructions à répéter
 La terminaison de la boucle
 La validité.

Quelle boucle utiliser : Pour la boucle for, le nombre d’itérations est connu à
l’avance et ce nombre est fixé dans la syntaxe de la boucle. Pour la boucle while
les instructions sont répétées un certain nombre de fois et le temps
d’exécution peut être plus ou moins long parfois infini (cas anormal).

for i in range(1,11) : for i in X : n=0


while n <= 0:
n -= 1
print("C’est fini !")
10 itérations X peut être une liste,
un tuple ou une chaîne Boucle infinie.
de caractères dans le
nombre d’éléments est
fini. Donc la boucle se
términe.

Les instructions à répéter : elles doivent être bien choisies afin d’atteindre
l’objectif, la validité du résultat escompter et d’assurer la terminaison de la
boucle.

La terminaison de la boucle : On doit se poser la question suivante : est-ce que


la boucle se termine et à quelles conditions ? Pour cela, on cherche dans la
boucle, ce qu’on appelle le variant de boucle. C’est une expression à valeurs
entières strictement décroissante et minorée.

Si ce variant prend un nombre fini de valeurs, alors on est certain que la boucle
se termine.
Mhamed AIT AAMMI HADI CPGE IBN GHAZI RABAT
2

Exemple :

def division(a,b): Remarquez que le variant de boucle ici est r


q,r=0,a puisqu’il décroit à chaque itération et il est
while r >= b: minoré par la valeur zéro. Donc le nombre
r=r-b d’opérations est fini.
q=q+1
return q,r

Remarque : Si on ne trouve pas une expression décroissante et minorée, alors


on cherche une expression croissante et majorée et on prend son
opposé pour avoir un variant de boucle.

La validité : A la fin d’une boucle qui se termine correctement, il faut s’assurer


que le résultat souhaité est atteint. Pour cela, on utilise un invariant de boucle.
C’est une proposition qui équivaut au résultat escompté et qui vérifie les
conditions ci-dessous :

 Cette proposition est vrai avant l’entrée dans la boucle.


 Si elle est vrai au début d’une itération, elle reste vrai à la fin de celle-
ci.

Selon ces deux principes, elle doit rester vrai à la fin de la boucle, ce qui
constitue une preuve de la validité du résultat.

Dans l’exemple de la fonction division(a,b), on souhaite que la proposition


a=bq+r soit vérifiée à la fin de la boucle while. Lorsqu’on vérifie, on constate
que ceci est vrai avec 0<= r <=b-1.

Complexité d’un algorithme

Généralités :

Deux programmes ou plus peuvent résoudre le même problème, cependant, la


taille des données stockées en mémoire, le nombre d’opérations exécutées et
la vitesse d’exécution des programmes peuvent être différents. Donc deux
paramètres deviennent très importants dans la complexité des algorithmes :

 Le temps d’exécution des programmes (Complexité temporelle)


 L’occupation de la mémoire (Complexité dans l’espace)

On souhaite donc que nos programmes soient le plus rapide possible et


utilisent le moins de mémoire.
Mhamed AIT AAMMI HADI CPGE IBN GHAZI RABAT
3

La complexité d’un programme donné et par convention la complexité de


l’algorithme le plus efficace permettant de le résoudre.

Remarque : Le cout des mémoires devient de plus en plus faible et leur


capacité de plus en plus grande, donc on va s’intéresser plus à la vitesse
d’exécution. Comme la vitesse d’exécution dépend du microprocesseur et donc
de la machine utilisée, on va utiliser des unités abstraites pour quantifier cette
vitesse.

Calcul de la complexité :

Les opérations élémentaires dans un programme peuvent être :

 Des opérations mathématiques de base ;


 Des opérations logiques (calculs sur les booléens, comparaisons, tests) ;
 Des affectations de variables ;
 Des incrémentations ou décrémentations des compteurs ;
 Des opérations d’affichage.
 Des retours de valeurs dans une fonction.

Par abréviation, on utilise « oe » pour ces opérations élémentaires et par


convention, chacune de ces opérations utilise une unité de temps.

En réalité, la consommation du temps peut différer d’une opération à l’autre,


d’une machine à l’autre, d’un langage à l’autre … La multiplication de deux
entiers par exemple, utilise plusieurs additions. Pour simplifier, on utilise le
même temps.

Exemple : Considérons, la fonction qui permet de calculer la somme des entiers


de zéro à n :

def Somme(n):  S et i sont initialisée à zéro : 2 oe


S=0  Pour chaque itération :
for i in range(n+1): o On incrémente i (i=i+1) : 1 oe
S=S+i o On compare i à n : 1 oe
return S o On calcul S+i : 1 oe
o On affecte S+i à S : 1 oe
o On retourne S : 1 oe
Donc le calcul de S avec la fonction Somme(n) va coûter 4n + 3 oe, on va dire
que la complexité à pour ordre de grandeur n et on va le noter O(n).

Définition : Le paramètre de complexité d’un algorithme est le paramètre qui


fait varier son temps d’exécution.

Pour la fonction Somme, ce paramètre c’est n. Si la somme se fait sur une liste,
le paramètre n sera la taille de la liste. Généralement, le nombre d’opérations
élémentaires dépend des valeurs prises par les entrées des programmes et de
celles transmises à une fonction.
Mhamed AIT AAMMI HADI CPGE IBN GHAZI RABAT
4

Exemple : considérons la recherche séquentielle d’un élément dans une liste :

 Si l’élément n’existe pas, on va passer en revue tous les éléments de la


liste.
 S’il existe à la position i, on va passer en revue uniquement i éléments.

On sera donc emmené à étudier les complexités ci-dessous :


 La complexité dans le meilleur des cas : nombre d’opérations réduit
par rapport aux autres cas.
 La complexité dans le pire des cas : c’est la majoration du nombre
d’oe.
 La complexité moyenne, c’est la moyenne du nombre d’oe. Ceci est
intéressant lorsqu’on exécute le programme plusieurs fois avec des
entrées différentes.

Différentes complexités : pour un algorithme de complexité n, les ordres de


grandeur de complexités usuelles sont consignés dans le tableau ci-dessous :

O(1) Temps constant. Cas très rare puisque les traitement ne


dépend pas des données.
0(ln n) temps logarithmique Très rapide exemple recherche
dichotomique.
O(n) temps linéaire Recherche séquentielle dans une liste.
Le temps dépend de la valeur de n.
O(n ln n) Temps linéarithmique Certain tri, le temps est plus grand que
ou dans O(n)
Quasi-linéaire.
0(n2) Temps quadratique. Programmes se basant sur deux
boucles imbriquées.
O(np ) temps polynomiale Le temps est plus important puisqu’il
dépend d’une puissance de n. se
retrouve dans des boucles imbriquées.
C’est le cas de certains tris.
O(pn ) temps exponentiel Temps élevé.

Classes de Complexité :
Mhamed AIT AAMMI HADI CPGE IBN GHAZI RABAT
5

Exemple de temps d’exécution :

Exemple 1 :

x=int(input("Donner un entier : ")) 3 oe : lecture+conversion+afectation


if x%2==0: 2 oe : Modulo+teste
print("Pair") 1 oe
else:
print("Impair") 1 oe
La complexité de ce programme est C(Exemple1)= 3+2+1+1 = 7 on dit que la
complexité est de 0(1).

Exemple 2 :

for i in range(10): Print(i) va se répéter 10 fois ( de 0 jusqu’à 9) : 10 oe


print(i) On dit que la complexité est de 0(1)

Exemple 3 :

for i in range(n): Print(i) va se répéter n fois ( de 0 jusqu’à n-1) : n oe


print(i) On dit que la complexité est de 0(n).

𝐶(𝐸𝑥𝑒𝑚𝑝𝑙𝑒3) = ∑𝑛𝑘=0 1 = n donc l’algo est en 0(n)


Mhamed AIT AAMMI HADI CPGE IBN GHAZI RABAT
6

Exemple 4 :

n=int(input("Donner un entier : ")) 3 oe + 1 oe(i=0)


for i in range(n):
for j in range(n): 2*n oe 2*n*n oe 2*n2 + 3 oe
print(i,j) 2 oe

La complexité de l’algorithme est de C(Exemple4) = 2*n*n + 3 oe = O(n2)

Exemple 4 :

def fact(n):
f=1 1 oe
for i in range(2,n+1):
f=f*i 2 oe f*i et f=. 2*(n-1) 1+2*(n-1)+1
return(f) 1 oe
n=10 1 oe
x= fact(n) 1 + 1 + 1 +2*(n-1)+1 = 4 + 2*(n-1)  0(n)
C(Exemple4) = 0(n)

Exemple 5 :

def premier(n):
i=2 1 oe
while i<=n//2 and n%i!=0: 4 oe dision+test+modulo+test
i+=1 2 oe : addition + affectation log2(n)

if i<=n//2: 2 oe division + test


return False 1 oe
return True 1 oe

Complexité(Exemple5)= 9+2log2(n) on dit que c’est en 0(log2(n))

Exemple 6 : Complexité d’une fonction récursive.

def factrec(n):
if n==0: C(n)=C(n-1)+1 avec C(0)=1
return 1
return n*factrec(n-1) Donc C(factrec)=O(n)

La complexité d’une fonction récursive dépend du traitement réalisé et du


nombre d’appel de la fonction à elle-même.

Vous aimerez peut-être aussi