Académique Documents
Professionnel Documents
Culture Documents
la Complexté Algorithmique
Cours et exercices
Filière SMI
2016-2017
Mustapha kchikech
Département de Mathématiques
et Informatique
Faculté Polydsciplinaire-Safi
Université Cadi Ayyad
Table des matières
Introduction iii
1 Complexité algorithmique 1
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Complexité des algorithmes . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.2 Complexité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.3 Analyse des algorithmes . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.3.1 Taille des données . . . . . . . . . . . . . . . . . . . . . . 4
1.2.3.2 Le temps d’exécution . . . . . . . . . . . . . . . . . . . . 5
1.2.3.3 Évaluation des coûts . . . . . . . . . . . . . . . . . . . . . 5
1.2.3.4 Objectif . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.3.5 Évaluation du temps de calcul . . . . . . . . . . . . . . . 6
1.2.3.6 Évaluation de T(n) . . . . . . . . . . . . . . . . . . . . . 6
1.2.4 Notation asymptotique . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.4.1 Pourquoi une analyse asymptotique ? . . . . . . . . . . . 7
1.2.4.2 Définition Θ-Notation . . . . . . . . . . . . . . . . . . . 8
1.2.4.3 Définition, O-Notation . . . . . . . . . . . . . . . . . . . 9
1.2.4.4 Complexité d’un algorithme . . . . . . . . . . . . . . . . 9
1.2.4.5 Classes de complexité . . . . . . . . . . . . . . . . . . . . 9
1.2.4.6 Hiérarchie entre les classes de complexité . . . . . . . . . 10
ii TABLE DES MATIÈRES
2 Réurrence 13
2.1 Présentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2 Résolution des récurrences . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.1 Méthode itérative . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2.2 Méthode de substitution . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2.3 Méthode générale . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2.4 DIVISER-POUR-RÉGNER . . . . . . . . . . . . . . . . . . . . . . 20
2.3 Résolution des récurrences . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3.1 Théorème général : . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3.1.1 Signification intuitive du théorème . . . . . . . . . . . . . 22
2.4 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Introduction
Complexité algorithmique
1.1 Introduction
Exemple 1.
— Algorithmes d’Euclide :
Entrée : deux entiers naturels a,b
Sortie : pgcd(a,b)
— Calcul de puissance :
Entrée : deux entiers naturels a,n
Sortie : an
— Algorithmes de tri :
Entrée : un tableau de n entiers tab = [a0 , a1 , · · · , an−1 ]
Sortie : un tableau de n entiers tab = [b0 , b1 , · · · , bn−1 ] t.q. b0 ≤ b1 ≤ · · · ≤ bn−1
— Algorithme de recherche dans un arbre binaire de recherche :
Entrée : un arbre binaire de recherche, une valeur v
Sortie : une réponse : la valuer figure oui ou non dans l’arbre
— Test de primalité :
Entrée : un entier naturel n
Sortie : une réponse : n est premier oui ou non
— ···
1.2.1 Motivation
— Un algorithme est dit correct si, pour chaque donnée en entrée, il doit fournir la
bonne sortie.
— Dans ce cas, on dit que l’algorithme (correct) résout le problème donné.
— Pour résoudre informatiquement un problème donné, on implante donc un al-
gorithme sur un ordinateur. C-à-d, l’algorithme sera réécrit avec un langage de
programmation.
1.2 Complexité des algorithmes 3
— Mais, pour un problème donné, il existe bien souvent plusieurs algorithmes qui le
résout.
— Ces algorithmes diffèrent entre eux en termes d’efficacité. Ces différences peuvent
être bien plus importantes que celles dues au matériel et au logiciel.
— Y a-t-il un intérêt à choisir des algorithmes ? et si oui comment choisir ?
1.2.2 Complexité
Remarque 1.
— La résolution informatique d’un problème donné passe par un algorithme qui est
implémenté par un langage de programmation.
— L’exécution d’un programme a un coût. Il existe deux paramètres essentiels pour
évaluer ce coût :
— le temps d’exécution : la complexité temporelle
4 Complexité algorithmique
Si l’on prend en compte tous les paramètres : fréquence d’horloge, nombre de proces-
seurs, temps d’accès disque,... l’estimation de ces ressources peut :
— être assez compliquée, voire irréalisable,
— devenir irréaliste dès que l’on change d’architecture.
— Pour cela on se contente souvent d’estimer l’influence de la taille des données sur
la taille des ressources nécessaires. Ainsi,
— Le temps d’exécution d’un algorithme sur une entrée particulière est le nombre
d’opérations élémentaire (affectations, comparaisons, opérations arithmétiques),
exécutées.
— Le temps d’exécution du programme dépend :
— des données du problème pour cette exécution
— de la qualité du code engendré par le compilateur
— de la nature et de la rapidité des instructions offertes par l’ordinateur
— de l’efficacité de l’algorithme
— de l’encodage des données
— ... et aussi de la qualité de la programmation
— En général, on ne peut pas mesurer le temps de calcul sur toutes les entrées
possibles. Il faut trouver une autre méthode d’évaluation.
— L’idée est d’évaluer le temps de calcul en fonction d’une grandeur n représentant
la taille des données.
1.2.3.4 Objectif
Traitement T1 (n)
··· ⇒T (n) = T1 (n) + T2 (n) + · · · + Tp (n)
Traitement T (n)
p
si (condition logique) alors
Traitement T1 (n)
⇒T (n) = max(T1 (n), T2 (n))
sinon
Traitement T (n)
2
— En pratique une analyse précise d’un algorithme même dans le pire des cas est
presque impossible (sauf pour un algorithme simple).
— La solution est d’établir une approximation asymptotique du temps de calcul de
l’algorithme. Autrement, on fait une analyse asymptotique.
— On veut comparer des algorithmes différents sans les implémenter, sans développer
des programmes. Pour faire ça on compare l’efficacité asymptotique des algo-
rithmes.
8 Complexité algorithmique
— Ceci revient à dire que f (n) est égale à g(n) à un facteur constant près.
— Pour indiquer que f (n) ∈ Θ(g(n)), on écrit
f (n) = Θ(g(n))
Exemple 5.
pour tout n ≥ n0
1 2
c1 n2 ≤ 2n − 3n ≤ c2 n2
1 3
c1 ≤ 2 − n ≤ c2
Prenons c2 = 12 , on a
1 3
∀n ≥ 1, − ≤ c2
2 n
1
Prenons c1 = 14 , on a
1 3
∀n ≥ 7, c1 ≤ −
2 n
1
On prend donc n0 = 7, c1 = 14 et c2 = 12 .
On peut établir une hiérarchie entre les classes de complexité du plus petit au plus
grand :
— O(1)→O(log(n))→O(n)→O(nlog(n))→O(n2 )→O(nk )→O(an )
1.2 Complexité des algorithmes 11
k > 2, a > 1.
— Comparaison :
somme=0;
for(i=1; i<=n; i++)
somme += n;
——————————————-
somme=0;
for (j=1; j<=n; j++)
a for (i=1; i<=n; i++)
a somme++;
for (k=0; k<n; k++)
a A[k] = k;
——————————————-
somme = 0;
for (i=1; i<=n; i++)
a for (j=1; j<=i; j++)
somme++;
12 Complexité algorithmique
——————————————-
somme = 0;
for (i=1; i<=n; i*=2)
a for (j=1; j<=n; j++)
a somme++;
2. Pour chacun des problèmes suivants, écrire en langage C une fonction itérative
qui permet de le résoudre et donner sa complexité.
Réurrence
2.1 Présentation
— Une récurrence est une équation ou une inégalité qui décrit une fonction à partir
de sa valeur sur des entrées plus petites.
— une fonction est récursive si elle fait appel à elle-même d’une manière directe ou
indirecte.
— Un algorithme est dit récursif si son temps de calcul peut être décrit par une
récurrence.
14 Réurrence
Remarque 2.
Suite de Fibonacci
— La suite de Fibonacci est définie par :
u0 = u1 = 1
n+2 = un+1 + un si n ≥ 2
u
T (0) = T (1) = 1
T (n) = T (n − 2) + T (n − 1) si n ≥ 2
— C’est une équation de récurrence où chaque terme d’ordre ≥ 2 dépend unique-
ment des 2 termes qui le précèdent.
— La solution de l’équation de récurrence est
√ √ √ √
5 + 5 1 + 5 n 5 − 5 1 − 5 n
T (n) = +
10 2 10 2
√
1+ 5 n
— T (n) =O 2 .
— La complexité de cet algorithme est donc exponentielle !
Dans ce chapitre, nous allons proposer trois méthodes de résolution des récurrences,
c-à-d pour obtenir des bornes asymptotiques Θ ou O pour la solution.
— Méthode itérative
— Méthode de substitution
— Méthode générale
16 Réurrence
Remarque 3.
Exemple 6.
n
T (n) = 2T ( ) + 2n + 1
2
2.2 Résolution des récurrences 17
n
T (n) = 2n + 1 + 2T ( )
2
n
= 2n + 1 + 2(n + 1 + 2T ( ))
4
n n
= 2n + 1 + 2(n + 1 + 2( + 1 + 2T ( )))
2 4
n
= 3(2n) + 1 + 2 + 4 + 23 T ( )
4
= ···
i−1
P j n
= 2in + 2 + 2i T ( i )
j=0 2
n
On arrive à T (1) lorsque = 1, c-à-d lorsque i = log(n). Ainsi,
2i
log(n)−1
2j + nT (1)
P
T (n) = 2n log(n) +
j=0
= 2n log(n) + n − 1 + n Θ(1)
= 2n log(n) + n − 1 + Θ(n)
Exemple 7.
n
T (n) = 3T ( ) + n
4
n
T (n) = n + 3T ( )
4
n n
= n + 3( + 3T ( 2 ))
4 4
n n n
= n + 3( + 3( 2 + 3T ( 3 )))
4 4 4
3 3 2 3 n
= n + n + ( ) n + 3 T( 3)
4 4 4
= ···
i−1
P 3 j n
= ( ) n + 3i T ( i )
j=0 4 4
18 Réurrence
n
On arrive à T (1) lorsque = 1, c-à-d lorsque i = log4 (n). Ainsi,
4i
3
T (n) = 4n(1 − ( )log4 (n) ) + 3log4 (n) T (1)
4
3 log4 (n)
= 4n(1 − ( ) ) + nlog4 (3) Θ(1) car 3log4 (n) = nlog4 (3)
4
3
= 4n + Θ(nlog4 (3) ) pour n assez grand ( )log4 (n) ≈ 0
4
Par conséquent T (n) = O(n)
Remarque 4.
Exemple 8.
n
T (n) = 2T ( ) + n
2
constante c > 0.
n n n
On suppose que T ( ) ≤ c log( ).
2 2 2
La substitution donne
2.2 Résolution des récurrences 19
n n
T (n) ≤ 2(c log( )) + n
2 2
n
≤ cn log( ) + n
2
= cn log(n) − cn log(2) + n
= cn log(n) − cn + n
≤ cn log(n) si c ≥ 1
Remarque 5.
— Montrer que
T (n) = O(log(n))
La méthode générale est une méthode qui s’appuie sur le théorème maı̂tre de la
complexité, il est connu comme Master theorem en anglais et on l’appelle Théorème
général en français.
— Elle est considérée comme une ”recette” pour résoudre les récurrences de la forme
n
T (n) = aT ( ) + f (n),
b
2.2.4 DIVISER-POUR-RÉGNER
sous-problème 1 solution 1
sous-problème 2 solution 1
sous-problème p solution 1
diviser régner combiner
Soient a ≥ 1 et b > 1 deux constantes, soit f (n) une fonction et soit T (n) définie
pour les entiers n ≥ 0 par la récurrence
n
T (n) = aT ( ) + f (n),
b
Dans chaque cas, on compare la fonction f (n) à la fonction nlogb (a) . La solution de la
récurrence est déterminée par la plus grande des deux.
— Cas 1 : nlogb (a) est la plus grande T (n) = Θ(nlogb (a) ).
— Cas 2 : f (n) est la plus grande T (n) = Θ(f (n)).
— Cas 3 : f (n) = nlogb (a) , T (n) = Θ(nlogb (a) log(n)).
Remarque 6.
Exemple 9.
n
T (n) = 9T ( ) + n
3
2.4 Exercices 23
Exemple 10.
2n
T (n) = T ( )+1
3
3
Pour cette récurrence, on a a = 1, b = 2 et f (n) = 1.
(log 3 (1))
On a donc nlogb (a) = n 2 = n0 = 1. On est dans le cas 2 puisque f (n) =
Θ(nlogb (a) ) = Θ(1).
La solution de la récurrence est donc T (n) = Θ(log(n)).
Exemple 11.
n
T (n) = 3T ( ) + n log(n)
4
Pour cette récurrence, on a a = 3, b = 4 et f (n) = n log(n).
On a donc nlogb (a) = nlog4 (3) = O(n0.793 ). Puisque f (n) = Ω(nlog4 (3)+ε ), avec ε ' 0.2, on
est dans le cas 3.
Pour n suffisamment grand, a f ( n4 ) = 3 n4 log( n4 ) ≤ 3 n4 log(n) = c f (n) avec c = 3
4 < 1.
Par conséquent, D’après le cas 3, on peut dire que T (n) = Θ(n log(n)).
Exemple 12.
n
T (n) = 2T ( ) + n log(n)
2
On a a = 2, b = 2 et f (n) = n log(n). On a donc nlogb (a) = nlog2 (2) = n. Dans ce cas, le
théorème général ne s’applique pas à la récurrence. En effet,
On pourrais penser que le cas 3 s’applique, puisque f (n) est plus grande asymptotique-
f (n)
ment que nlogb (a) = n. Le problème est que nlogb (a)
= log(n) est asymptotiquement plus
petit que nε , ∀ε > 0.
2.4 Exercices
Exercice 1 :
24 Réurrence
Pour chacune des fonctions suivantes, déterminer le temps de calcul dans le pire des
cas et en O() en justifiant votre réponse :
Exercice 2 :
(e) parcourir un arbre binaire et rechercher un élément dans un arbre binaire AVL.
Exercice 3 :
1. Donnez des bornes asymptotiques approchées pour T (n) dans chacun des récurrences
suivantes :
(a) T (n) = 4T ( n2 ) + n.
(b) T (n) = 4T ( n2 ) + n3 .
√
(c) T (n) = 2T ( n2 ) + n.
√ √
(d) T (n) = nT ( n) + n.
int fonct(int n)
{
if(n<2) return 1;
else return 4*fonct(n-1)-2*fonct(n-2);
}
26 Réurrence
(b) Calculer la complexité dans le pire des cas et en O() de cette fonction. Ce
programme est-il efficace ?
(c) Proposer une autre fonction en O(n) pour effectuer le même traitement.
Exercice 5 :
Exercice 4 :
Le tri fusion est une méthode algorithmique basée sur la technique ”diviser pour
régner”. Le principe de cette méthode peut être décrit par l’algorithme récursif suivant :
— On divise la liste en deux parties presque de même tailles,
— On trie les deux parties,
— On fusionne les deux parties.
Ce processus de la récursivité s’arrête une fois la décomposition des sous-listes donnent
des sous-listes composées d’un seul élément et le tri est alors trivial.