0% ont trouvé ce document utile (0 vote)
2 vues26 pages

Cours 4

Transféré par

oscar.ilyas
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
2 vues26 pages

Cours 4

Transféré par

oscar.ilyas
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Complexité

Listes
Conclusion

Complexité d’un algorithme


Application aux listes

Alix Munier-Kordon et Maryse Pelletier

LIP6
Sorbonne Université
Paris

LU2IN003 Initiation à l’algorithmique

1
Complexité
Listes
Conclusion

Plan du cours

1 Complexité
Introduction
Complexité d’un algorithme
Exemples de calculs de complexité
Méthodologie

2 Listes
Définition, représentation, primitives
Complexité

3 Conclusion

2
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Questions au sujet de l’évaluation d’un algorithme

1 Est-ce que l’algorithme résout le problème ?


terminaison
validité
2 Quelle est la complexité de l’algorithme ?
en temps de calcul
en taille mémoire
Objet de ce cours : la complexité en temps de calcul.

3
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Taille de codage des paramètres d’un algorithme

Definition
La taille de codage d’un paramètre est une évaluation, la plus
"raisonnable" possible, de la place nécessaire en mémoire pour
le stocker.
Quelle est la taille de codage d’un entier ? d’un tableau
d’entiers ?

4
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Complexité d’un algorithme

Definition
La complexité d’un algorithme est une évaluation du nombre
d’instructions élémentaires1 dans une exécution de
l’algorithme.

On l’exprime en fonction de la taille de codage des paramètres.


On en calcule un ordre de grandeur (notations de Landau).

1
Parfois on se concentre sur une instruction élémentaire représentative.
5
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Pire cas, meilleur cas

Complexité pire cas : on évalue le nombre d’instructions dans


le pire des cas (borne supérieure).
Complexité meilleur cas : on évalue le nombre d’instructions
dans le meilleur des cas (borne inférieure).
Exemple : recherche séquentielle d’un élément x dans un tableau T de taille n.
Instruction élémentaire représentative : comparaison.
Pire cas : x en dernière place de T ou pas présent → n comparaisons
Meilleur cas : x en première place de T → 1 comparaison

Par pessimisme, on identifie la complexité d’un algorithme avec


sa complexité dans le pire des cas.
La complexité de la recherche séquentielle est en O(n).

6
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Comparaison de complexités
Avec une durée de 10−6 secondes par instruction, on obtient les
durées suivantes (en secondes) pour n = 100

complexité durée
ln(n) 4, 60 × 10−6
n 10−4
n ln(n) 4, 60 × 10−4
n2 10−2
n3 1
2n ≈ 1, 27 × 1024
Remarque : 1, 27 × 1024 secondes ≈ 4 × 1016 ans !
Un algorithme de complexité logarithmique est meilleur qu’un
algorithme de complexité linéaire, meilleur qu’un algorithme de
complexité quadratique, etc.
Un algorithme de complexité exponentielle est à bannir.
7
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Somme des entiers

Pour n ∈ N, on veut calculer la somme Som(n) des entiers de 0


à n.
Autrement dit :
n
X
Som(n) = i
0

Cette somme vaut 0 si n = 0.

8
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Somme des entiers, en itératif


Algorithme itératif calculant la somme Som(n) :

def somIte(n):
res = 0
for i in range(1, n + 1):
res = res + i
return res

Complexité en nombre d’additions.


Soit c le nombre total d’additions et ci le nombre d’additions dans le tour de boucle i.
Alors ci = 1 pour tout i ∈ {1, . . . , n} et

n
X
c= ci = n
i=1

La complexité est en Θ(n), elle est linéaire.


9
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Somme des entiers, en récursif


Remarquons que Som(n) = Som(n − 1) + n si n > 0 et Som(0) = 0.
Algorithme récursif calculant la somme Som(n) :
def somRec(n):
if n == 0:
return 0
else:
return n + somRec(n - 1)
Complexité en nombre d’opérations : tests et additions.
Soit un le nombre d’opérations effectuées par l’appel somRec(n).
Alors un est la suite récurrente définie par :

un = un−1 + 2 si n > 0 et u0 = 0

Par substitution :

un = un−1 + 2 = un−2 + 4 = . . . = u0 + 2n = 2n + 1

La complexité est en Θ(n).


10
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Fibonacci, en itératif
Algorithme itératif calculant Fn :

def fibIte(n):
if (n == 0):
return 0
else:
x = 0 ; y = 1
for i in range(2, n + 1):
z = x + y ; x = y ; y = z
return y

Complexité en nombre d’additions.


Soit c le nombre total d’additions et ci le nombre d’additions dans le tour de boucle i.
Alors ci = 1 et
X n
c= ci = n − 1
i=2

La complexité en Θ(n).
Remarque : la complexité en nombre d’affectations est aussi linéaire.
11
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Fibonacci, en récursif

Algorithme récursif calculant Fn :

def fibRec(n):
if (n == 0) or (n == 1):
return n
else:
return fibRec(n - 1) + fibRec(n - 2)

Pour simplifier, on évalue la complexité en nombre d’additions.


Soit un le nombre d’additions effectuées par l’appel fibRec(n).
Alors un est la suite récurrente définie par :

un = un−1 + un−2 + 1 si n > 1 et u0 = u1 = 0

12
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Fibonacci, en récursif

un = un−1 + un−2 + 1 si n > 1 et u0 = u1 = 0

Theorem
un = Fn+1 − 1.
Preuve par récurrence.

Theorem

√1 (ϕn 1+ 5
Fn ≥ 5
− 1) où ϕ est le nombre d’or : ϕ = 2 ≈ 1, 618.

Preuve par récurrence.


La complexité est en Ω(ϕn ). Comme ϕ > 1, elle est exponentielle.
Elle croît très vite, par exemple : ϕ100 > 7, 9 ∗ 1020 .
13
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Calcul de la puissance : un premier algorithme

Algorithme basé sur la définition récursive naturelle de x n :

x n = x ∗ x n−1 si n > 0 et x 0 = 1

def puissSeq(x, n):


if (n == 0):
return 1
else:
return x * puissSeq(x, n - 1)

La complexité, en nombre de multiplications, est en Θ(n).

14
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Calcul de la puissance par dichotomie

On peut faire un calcul de x n par dichotomie :



 1 si n = 0
n n÷2 2
x = (x ) si n pair et n > 0
 n÷2 2
(x ) × x si n impair

où n ÷ 2 est le résultat de la division entière de n par 2.

15
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Calcul de la puissance par dichotomie : algorithme

Algorithme calculant x n par dichotomie :

def puissDicho(x, n):


if (n == 0):
return 1
else:
if n % 2 == 0:
return carre(puissDicho(x, n // 2))
else:
return carre(puissDicho(x, n // 2)) * x

où la fonction carre est ainsi définie :

def carre(x):
return x * x

16
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Calcul de la puissance par dichotomie : complexité


Soit un le nombre de multiplications effectuées par l’appel puissDicho(n).

 0 si n = 0
un = un÷2 + 1 si n pair et n > 0
un÷2 + 2 si n impair et n > 0

Dans tous les cas, pour n > 0, on a un ≤ un1 + 2 où n1 = n ÷ 2.

un ≤ un1 + 2 avec n1 = n ÷ 2
≤ un2 + 4 avec n2 = n1 ÷ 2 = n ÷ 22
≤ un3 + 6 avec n3 = n2 ÷ 2 = n ÷ 23
≤ ...
≤ unk + 2 ∗ k avec nk = n ÷ 2k

Les calculs s’arrêtent lorsque nk = 0, c’est-à-dire lorsque k = blog2 (n)c + 1.


Donc un ≤ 2 ∗ blog2 (n)c + 2.
La complexité est en O(log2 (n)), elle est logarithmique.

17
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Un peu de méthodologie

Complexité d’un algorithme itératif :


évaluer la complexité ci du tour de boucle i,
calculer la somme des ci pour tous les tours de boucle.
Exemples :
somIte(n) : ci = 1 pour i ∈ {1, . . . , n} et il y a n tours de
boucle
fibIte(n), pour n ≥ 2 : ci = 1 pour i ∈ {2, . . . , n} et il y a
n − 1 tours de boucle.

18
Introduction
Complexité
Complexité d’un algorithme
Listes
Exemples de calculs de complexité
Conclusion
Méthodologie

Un peu de méthodologie

Complexité d’un algorithme récursif :


évaluer la complexité des cas de base,
établir une relation de récurrence permettant de calculer
cn . cn est exprimé en fonction des complexités des appels
récursifs et de la complexité b(n) des autres calculs.
Exemples :
somRec(n) : c0 = 1, cn = cn−1 + b(n) pour n > 0, avec
b(n) = 2
fibRec(n) : c0 = c1 = 0, cn = cn−1 + cn−2 + b(n) pour
n > 1, avec b(n) = 1
puissDicho(x, n) : c0 = 0, cn = cn÷2 + b(n) pour
n > 0, avec b(n) ≤ 2.

19
Complexité
Définition, représentation, primitives
Listes
Complexité
Conclusion

Notion de liste

Definition
Une liste L = (a0 , · · · , an ) est une succession d’éléments.

jour=[’lundi’, ’mardi’, ’mercredi’]


corbeille=[56, ’jeudi’, 45, 67, ’coucou’]

Quels points communs (différences) voyez-vous entre listes et


ensembles ?
Definition
La liste L est homogène si tous ses éléments sont de même
type.

20
Complexité
Définition, représentation, primitives
Listes
Complexité
Conclusion

Représentation des listes

Une liste peut être implémentée par :


un tableau,
une liste simplement chaînée,
une liste circulaire doublement chaînée.

21
Complexité
Définition, représentation, primitives
Listes
Complexité
Conclusion

Primitives et opérations sur les listes

L[i] : renvoie l’élément en position i dans la liste L (positions


numérotées à partir de 0);
L[i : j] : renvoie la sous-liste de L composée des éléments situés entre
la position i et la position j − 1 comprises;
[Link](x) : insertion de l’élément x en queue de la liste L;
L. insert(i, x) : insertion de l’élement x en i-ème place;
L. pop(i) : renvoie l’élément en i-ème position et le supprime de la liste;
[Link](x) : détruit la première instance de l’élément x dans la liste L;
len(L) : renvoie le nombre d’éléments de L;
[Link](x) : indice du premier élément de valeur x dans L;
L. count(x) : nombre d’occurrences de x dans L;
L1 + L2 : renvoie la concaténation des deux listes;
L ? k : crée une liste de k occurrences de L.

22
Complexité
Définition, représentation, primitives
Listes
Complexité
Conclusion

Complexité des primitives

Primitive Tableau Liste simpl. chaînée Liste doubl. circulaire


L[i] Θ(1) Θ(i) Θ(i)
[Link](x) O(n) Θ(n) Θ(1)
[Link](i,x) Θ(n − i) Θ(i) Θ(i)
[Link](i) Θ(n − i) Θ(i) Θ(i)
[Link](x) Θ(n) O(n) O(n)
[Link](x) O(n) O(n) O(n)
[Link](x) Θ(n) Θ(n) Θ(n)
L1 + L2 O(n1 + n2 ) Θ(n1 ) Θ(1)
L?k Θ(n × k ) Θ(n × k ) Θ(n × k )
len(L) Θ(1) Θ(n) Θ(n)
n = |L|, n1 = |L1 |, et n2 = |L2 |.

23
Complexité
Définition, représentation, primitives
Listes
Complexité
Conclusion

Exemple : fonction miroir

def swapp (tab, i, j):


aux = tab[i]; tab[i]=tab[j]; tab[j]=aux

def miroir(tab):
n = len(tab)
i = 0 ; j = n -1
while i < j:
swapp(tab, i, j)
i = i + 1; j = j - 1

24
Complexité
Définition, représentation, primitives
Listes
Complexité
Conclusion

Complexité de miroir en fonction de la représentation


de tab

len(tab) swapp(tab, i, j) miroir (tab)


Tableau Θ(1) Θ(1) Θ(n)
Liste simpl. chaînée Θ(n) Θ(max(i, j)) Θ(n2 )
Liste doubl. circulaire Θ(n) Θ(max(i, j)) Θ(n2 )
n = |tab|.

25
Complexité
Listes
Conclusion

Conclusion
Sur la complexité
Un même problème peut être résolu par différents algorithmes.
Il est important de connaître un ordre de grandeur de la
complexité de chaque algorithme.
Il faut proscrire les algorithmes de complexité exponentielle.
Sur les listes
Plusieurs représentations possibles des listes avec des
primitives d’accès et de gestion de complexité différentes.
Quand on évalue la complexité d’un algorithme, il faut connaître
précisement la complexité de toutes les primitives associées aux
structures de données.
Choisir la structure de données en fonction des traitements à
réaliser.
26

Vous aimerez peut-être aussi