introduction à la complexté algorithmique
TRANSCRIPT
Introduction à
la Complexté Algorithmique
Cours et exercicesFilière SMI2016-2017
Mustapha kchikech
Département de Mathématiques
et Informatique
Faculté Polydsciplinaire-Safi
Université Cadi Ayyad
Table des matieres
Introduction iii
1 Complexite algorithmique 1
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Complexite des algorithmes . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.2 Complexite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.3 Analyse des algorithmes . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.3.1 Taille des donnees . . . . . . . . . . . . . . . . . . . . . . 4
1.2.3.2 Le temps d’execution . . . . . . . . . . . . . . . . . . . . 5
1.2.3.3 Evaluation des couts . . . . . . . . . . . . . . . . . . . . . 5
1.2.3.4 Objectif . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.3.5 Evaluation du temps de calcul . . . . . . . . . . . . . . . 6
1.2.3.6 Evaluation de T(n) . . . . . . . . . . . . . . . . . . . . . 6
1.2.4 Notation asymptotique . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.4.1 Pourquoi une analyse asymptotique ? . . . . . . . . . . . 7
1.2.4.2 Definition Θ-Notation . . . . . . . . . . . . . . . . . . . 8
1.2.4.3 Definition, O-Notation . . . . . . . . . . . . . . . . . . . 9
1.2.4.4 Complexite d’un algorithme . . . . . . . . . . . . . . . . 9
1.2.4.5 Classes de complexite . . . . . . . . . . . . . . . . . . . . 9
1.2.4.6 Hierarchie entre les classes de complexite . . . . . . . . . 10
ii TABLE DES MATIERES
1.2.5 Exemples et exercices . . . . . . . . . . . . . . . . . . . . . . . . . 11
2 Reurrence 13
2.1 Presentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2 Resolution des recurrences . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.1 Methode iterative . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2.2 Methode de substitution . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2.3 Methode generale . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2.4 DIVISER-POUR-REGNER . . . . . . . . . . . . . . . . . . . . . . 20
2.3 Resolution des recurrences . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3.1 Theoreme general : . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3.1.1 Signification intuitive du theoreme . . . . . . . . . . . . . 22
2.4 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Introduction
Ce polycopie presente une introduction sur la complexite algorithmique et des notions
sur la recurrence en algorithmique. L’objectif est de presenter des concepts fondamentaux
de la theorie de la complexite algorithmique qui offrent un ensemble d’outils permettant
d’analyser, de comparer et d’optimiser des algorithmes par la suite des programmes
informatique.
Par consequent, ce document met egalement a la disposition des etudiants un sup-
port de cours qui pourrait leur permettre d’acquerir et d’ameliorer leurs competences en
programmation.
Notons que ce document est un support pedagogique qui s’adresse principalement aux
etudiants de la filiere SMI semestre 4 de la Faculte Poly-disciplinaire de Safi, universite
cadi Ayyad. Il pourrait egalement servir comme support de cours aux etudiants d’autres
filieres.
iv Introduction
Chapitre 1
Complexite algorithmique
1.1 Introduction
— Le mot algorithme provient du nom du mathematicien arabe du IXe siecle, Mo-
hammed Ibn-Moussa Al-Khuwarizmi (livre d’arithmetique).
— Autant dire que les algorithmes sont connus et utilises bien avant les debuts de
l’informatique.
— Premier algorithme est l’Algorithme d’EUCLIDE (300 avant JC) pour calculer le
plus grand diviseur commun de deux entiers.
— La notion actuelle d’algorithme a ete elaboree par les logiciens des annees 1930
(Herbrand, Godel, Church et Turing).
— En 1968, Knuth publia le premier ouvrage The Art of Computer Programming
sur l’etude moderne des algorithmes informatiques.
— Il existe differentes facons de definir un algorithme. C’est pourquoi, nous presentons
ici quelques definitions qui peuvent donner une idee sur la notion d’algorithme.
— Un algorithme est une procedure de calcul bien definie, qui prend en entree une
valeur, ou un ensemble de valeurs, et qui produit, en sortie, une valeur ou un
ensemble de valeurs. Un algorithme est donc une sequence d’etapes de calcul per-
mettant de passer de la valeur d’entree a la valeur de sortie.
2 Complexite algorithmique
— Un algorithme est une procedure de calcul specifique permettant d’obtenir une
relation desiree entre l’entree et la sortie d’un probleme.
— L’algorithmique est la branche de l’informatique qui traite des algorithmes.
Exemple 1.
— Algorithmes d’Euclide :
Entree : deux entiers naturels a,b
Sortie : pgcd(a,b)
— Calcul de puissance :
Entree : deux entiers naturels a,n
Sortie : an
— Algorithmes de tri :
Entree : 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 :
Entree : un arbre binaire de recherche, une valeur v
Sortie : une reponse : la valuer figure oui ou non dans l’arbre
— Test de primalite :
Entree : un entier naturel n
Sortie : une reponse : n est premier oui ou non— · · ·
1.2 Complexite des algorithmes
1.2.1 Motivation
— Un algorithme est dit correct si, pour chaque donnee en entree, il doit fournir la
bonne sortie.
— Dans ce cas, on dit que l’algorithme (correct) resout le probleme donne.
— Pour resoudre informatiquement un probleme donne, on implante donc un al-
gorithme sur un ordinateur. C-a-d, l’algorithme sera reecrit avec un langage de
programmation.
1.2 Complexite des algorithmes 3
— Mais, pour un probleme donne, il existe bien souvent plusieurs algorithmes qui le
resout.
— Ces algorithmes different entre eux en termes d’efficacite. Ces differences peuvent
etre bien plus importantes que celles dues au materiel et au logiciel.
— Y a-t-il un interet a choisir des algorithmes ? et si oui comment choisir ?
1.2.2 Complexite
En informatique, la notion de complexite signifie deux concepts :
— la complexite des algorithmes : C’est l’etude de l’efficacite comparee des algo-
rithmes.
— En effet, la complexite introduit la notion de cout et montre qu’il ne suffit pas
de trouver une methode correcte pour resoudre un probleme, il faut aussi que
cette methode soit efficace.
— L’efficacite est mesuree par le temps et l’espace necessaire a un algorithme
pour resoudre un probleme.
— La complexite des problemes : C’est l’etude qui permet classification des problemes
en fonction des performances des meilleurs algorithmes connus qui les resolvent.
Pour notre cours, on parlera de la complexite c’est pour designer la complexite
des algorithmes.
Remarque 1.
1.2.3 Analyse des algorithmes
— La resolution informatique d’un probleme donne passe par un algorithme qui est
implemente par un langage de programmation.
— L’execution d’un programme a un cout. Il existe deux parametres essentiels pour
evaluer ce cout :
— le temps d’execution : la complexite temporelle
4 Complexite algorithmique
— l’espace memoire requis : la complexite spatiale
— Ainsi, analyser un algorithme est une operation qui consiste a prevoir les res-
sources necessaires (memoire, temps de calcul) au programme qui implemente cet
algorithme.
— Pour pouvoir analyser un algorithme, il faut avoir un modele de la technologie
qui sera employee.
— En algorithmique, les algorithmes sont analyses selon les calculs dans un modele
generique de machine a acces aleatoires (RAM=Random Access Machine), a pro-
cesseur unique.
— Dans le modele RAM, les instructions sont executees l’une apres l’autre, sans
operations simultanees.
— En resume,
Analyse des algorithmes ⇐⇒ etude de la complexite des algorithmes
1.2.3.1 Taille des donnees
Si l’on prend en compte tous les parametres : frequence d’horloge, nombre de proces-
seurs, temps d’acces disque,... l’estimation de ces ressources peut :
— etre assez compliquee, voire irrealisable,
— devenir irrealiste des que l’on change d’architecture.
— Pour cela on se contente souvent d’estimer l’influence de la taille des donnees sur
la taille des ressources necessaires. Ainsi,
La taille des donnees depend du probleme etudie
— On appelle les entrees ou les instances la taille des donnees necessaires a un algo-
rithme pour resoudre un probleme donne.
— La taille n va dependre du codage de ces entrees
Exemple : en binaire, il faut blog2(n)c+ 1 bits pour coder l’entier n.
— En pratique, on choisit comme taille la ou les dimensions les plus significatives.
— Exemple :
1.2 Complexite des algorithmes 5
— des matrices m× n : max(m,n), m.n, m+ n
— des listes, tableaux, fichiers : nombre de cases, d’elements
— des chaınes de caracteres : leur longueur
1.2.3.2 Le temps d’execution
— Le temps d’execution d’un algorithme sur une entree particuliere est le nombre
d’operations elementaire (affectations, comparaisons, operations arithmetiques),
executees.
— Le temps d’execution du programme depend :
— des donnees du probleme pour cette execution
— de la qualite du code engendre par le compilateur
— de la nature et de la rapidite des instructions offertes par l’ordinateur
— de l’efficacite de l’algorithme
— de l’encodage des donnees
— ... et aussi de la qualite de la programmation
— En general, on ne peut pas mesurer le temps de calcul sur toutes les entrees
possibles. Il faut trouver une autre methode d’evaluation.
— L’idee est d’evaluer le temps de calcul en fonction d’une grandeur n representant
la taille des donnees.
1.2.3.3 Evaluation des couts
— P : un probleme et M : une methode pour resoudre le probleme P
— Algorithme A : description deM dans un langage donne (algorithmique, C/C++,
Java, ...)
— Structures de controle :
— sequence (suite d’instructions)
— embranchement (ou selection) : if() ou switch()
— boucle (ou iteration) : for(); do...while(); while()
6 Complexite algorithmique
1.2.3.4 Objectif
— Evaluer le temps de calcul de A pour P
— Comparer A avec un autre algorithme A′
— L’evaluation :
— depends de la taille du probleme,
— doit etre independante de la machine utilisee.
1.2.3.5 Evaluation du temps de calcul
— La complexite d’un algorithme ou l’evaluation du temps de calcul d’un algorithme
est une mesure exprimee en fonction de la taille n des donnees :
T(n)=nombre d’operations elementaires
— On distingue trois sortes de complexites :
— la complexite dans le pire des cas : calcul du cout dans le pire des cas,
Tpire(n) =maxnT (n)
— la complexite en moyenne : on calcule le cout pour chaque donnee possible
puis on divise la somme de ces couts par le nombre de donnees differentes,
Tmoyenne(n) = 1n
∑nT (n)
— la complexite dans le meilleur des cas : on calcule le cout en se placant dans
le meilleur des cas.
Tmeilleur(n) =minnT (n)
— Remarque : En analyse de complexite, on etudie souvent le pire cas ce qui donne
une borne superieure de la complexite de l’algorithme.
1.2.3.6 Evaluation de T(n)
— Sequence (sommes des couts) :
Exemple 2.
1.2 Complexite des algorithmes 7
TraitementT1(n)
· · ·
TraitementTp(n)
⇒T (n) = T1(n) + T2(n) + · · ·+ Tp(n)
— Embranchement (Max des couts) :
Exemple 3.
si (condition logique) alors
TraitementT1(n)
sinon
TraitementT2(n)
⇒T (n) = max(T1(n), T2(n))
— Boucle (Somme des couts de chaque passage) :
Exemple 4.Tant que (condition logique) faire
TraitementTi(n)
Fin faire
⇒T (n) =k∑iTi(n)
k =nombre de repetition du traitement Ti(n).
1.2.4 Notation asymptotique
1.2.4.1 Pourquoi une analyse asymptotique ?
— En pratique une analyse precise d’un algorithme meme dans le pire des cas est
presque impossible (sauf pour un algorithme simple).
— La solution est d’etablir une approximation asymptotique du temps de calcul de
l’algorithme. Autrement, on fait une analyse asymptotique.
— On veut comparer des algorithmes differents sans les implementer, sans developper
des programmes. Pour faire ca on compare l’efficacite asymptotique des algo-
rithmes.
8 Complexite algorithmique
1.2.4.2 Definition Θ-Notation
Soient f et g deux fonctions de N dans R.
— On dit que g(n) est une borne approchee asymptotique pour f(n) et l’on ecrit
f(n) ∈ Θ(g(n)) s’il existe deux constantes strictement positives c1 et c2 telles que,
pour n assez grand, on ait
0 ≤ c1g(n) ≤ f(n) ≤ c2g(n)
— Ceci revient a dire que f(n) est egale a g(n) a un facteur constant pres.
— Pour indiquer que f(n) ∈ Θ(g(n)), on ecrit
f(n) = Θ(g(n))
Exemple 5.
— Montrons que f(n) = 12n
2 − 3n = Θ(n2).
— On doit trouver c1, c2, n0 > 0 telles que
1.2 Complexite des algorithmes 9
pour tout n ≥ n0c1n
2 ≤ 12n
2 − 3n ≤ c2n2
c1 ≤ 12 −
3n ≤ c2
Prenons c2 = 12 , on a
∀n ≥ 1,1
2− 3
n≤ c2
Prenons c1 = 114 , on a
∀n ≥ 7, c1 ≤1
2− 3
n
On prend donc n0 = 7, c1 = 114 et c2 = 1
2 .
1.2.4.3 Definition, O-Notation
Soient f et g deux fonctions de N dans R.
— On dit que g(n) est une borne superieure asymptotique pour f(n) et l’on ecrit
f(n) ∈ O(g(n)) s’il existe une constante strictement positive c telle que pour n
assez grand on ait
0 ≤ f(n) ≤ cg(n)
— Ceci revient a dire que f(n) est inferieure a g(n) a une constante pres et pour n
assez grand.
— Pour indiquer que f(n) ∈ O(g(n)), on ecrit
f(n) = O(g(n))
1.2.4.4 Complexite d’un algorithme
— Un algorithme A resout un probleme P en temps O(f(n)) si pour toute instance
de taille n, l’algorithme retourne une solution correcte avec un cout O(f(n)).
— La nature de la fonction f(n) definie la classe de complexite de l’algorithme A.
1.2.4.5 Classes de complexite
Lors de l’analyse de complexite, on essaie de se ramener aux classes suivantes :
10 Complexite algorithmique
— temps constant :Cout : O(1) Exemple : addition, affectation...
— Complexite logarithmique : Cout : O(log(n))
Exemple : recherche dichotomique dans un tableau trie A[1...n]
— Complexite lineaire : Cout : O(n) Exemple : calcul du produit scalaire de deux
vecteurs de Rn
— Complexite quasi-lineaire : Cout : O(nlog(n))
Exemple : Tri par fusion
— Complexite polynomial : Cout : O(nk), k > 1, pour k = 2, on parle de la Com-
plexite quadratique Exemple : Multiplication de deux matrices carrees d’ordre n :
O(n3)
— Complexite exponentielle : Cout : O(an) avec a > 1
Exemple : Tours de Hanoı
1.2.4.6 Hierarchie entre les classes de complexite
On peut etablir une hierarchie entre les classes de complexite du plus petit au plus
grand :
— O(1)→O(log(n))→O(n)→O(nlog(n))→O(n2)→O(nk)→O(an)
1.2 Complexite des algorithmes 11
k > 2, a > 1.
— Comparaison :
1.2.5 Exemples et exercices
1. Quelle est la complexite de ces parties de programme ?
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 Complexite algorithmique
——————————————-
somme = 0;
for (i=1; i<=n; i*=2)
a for (j=1; j<=n; j++)
a somme++;
2. Pour chacun des problemes suivants, ecrire en langage C une fonction iterative
qui permet de le resoudre et donner sa complexite.
(a) Puissance n-eme d’un entier.
(b) Suite de Fibonacci.
(c) Tri des tableaux.
(d) Test de Primalite d’un entier.
Chapitre 2
Reurrence
2.1 Presentation
— Une recurrence est une equation ou une inegalite qui decrit une fonction a partir
de sa valeur sur des entrees plus petites.
— une fonction est recursive si elle fait appel a elle-meme d’une maniere directe ou
indirecte.
— Un algorithme est dit recursif si son temps de calcul peut etre decrit par une
recurrence.
14 Reurrence
— L’utilisation des algorithmes recursifs est une technique de programma-
tion qui permet de trouver des solutions d’une grande elegance a un
certain nombre de problemes.
— Dans un algorithme recursif, la recursivite doit s’arreter a un moment
donne (test d’arret). Autrement, l’execution va continuer indefiniment.
— Ce processus est connu sous le nom du processus de reduction qui a
chaque appel, on doit se rapprocher de la condition d’arret.
— Attention ! : lorsqu’elle mal utilisee, on peut creer un code de programme
totalement inefficace.
Remarque 2.
Suite de Fibonacci
— La suite de Fibonacci est definie par : u0 = u1 = 1
un+2 = un+1 + un si n ≥ 2
— Un algorithme recursif qui calcule le nieme terme de cette suite :
int fib(int n)
a if(n<=1)
a return 1;
a else
a return fib(n-1)+fib(n-2);
— Complexite :
— Soit T (n) =nombre d’additions effectuees par cet algorithme lors du calcul.
— T (n) verifie les equations suivantes :
2.2 Resolution des recurrences 15
T (0) = T (1) = 1
T (n) = T (n− 2) + T (n− 1) si n ≥ 2
— C’est une equation de recurrence ou chaque terme d’ordre ≥ 2 depend unique-
ment des 2 termes qui le precedent.
— La solution de l’equation de recurrence est
T (n) =5 +√
5
10
(1 +√
5
2
)n+
5−√
5
10
(1−√
5
2
)n
— T (n) =O((
1+√5
2
)n).
— La complexite de cet algorithme est donc exponentielle !
2.2 Resolution des recurrences
Dans ce chapitre, nous allons proposer trois methodes de resolution des recurrences,
c-a-d pour obtenir des bornes asymptotiques Θ ou O pour la solution.
— Methode iterative
— Methode de substitution
— Methode generale
16 Reurrence
— En pratique, quand on definit et resout des recurrences, on omet souvent
les parties entieres et les conditions aux limites.
— En fait, ces details n’affectent pas les bornes asymptotiques des
recurrences rencontrees dans l’analyse des algorithmes. En effet :
— On passe souvent sur le fait que les arguments des fonctions sont
des entiers. Normalement, le temps d’execution T (n) d’un algorithme
n’est definit que pour n entier puisque, dans la plupart des algo-
rithmes, la taille de l’entree a toujours une valeur entiere.
— Le plus souvent on ignore les conditions aux limites. Puisque le
temps d’execution d’un algorithme sur une entree de taille constante
est une constante, les recurrences sous-jacentes au calcul du temps
d’execution des algorithmes ont generalement T (n) = Θ(1) pour n
suffisamment petit. Ainsi, pour simplifier, on suppose generalement
que T (n) est constant pour n petit.
Remarque 3.
2.2.1 Methode iterative
— L’idee de la methode consiste a developper la recurrence en sommation.
— On utilise les techniques d’evaluation des sommations pour trouver les bornes a
la solution.
— Cette methode necessite plus de manipulations algebriques.
Exemple 6.
T (n) = 2T (n
2) + 2n+ 1
2.2 Resolution des recurrences 17
On developpe comme suit :
T (n) = 2n+ 1 + 2T (n
2)
= 2n+ 1 + 2(n+ 1 + 2T (n
4))
= 2n+ 1 + 2(n+ 1 + 2(n
2+ 1 + 2T (
n
4)))
= 3(2n) + 1 + 2 + 4 + 23T (n
4)
= · · ·
= 2in+i−1∑j=0
2j + 2iT (n
2i)
On arrive a T (1) lorsquen
2i= 1, c-a-d lorsque i = log(n). Ainsi,
T (n) = 2n log(n) +log(n)−1∑
j=02j + nT (1)
= 2n log(n) + n− 1 + nΘ(1)
= 2n log(n) + n− 1 + Θ(n)
Par consequent T (n) = O(n log(n))
Exemple 7.
T (n) = 3T (n
4) + n
On developpe comme suit :
T (n) = n+ 3T (n
4)
= n+ 3(n
4+ 3T (
n
42))
= n+ 3(n
4+ 3(
n
42+ 3T (
n
43)))
= n+3
4n+ (
3
4)2n+ 33T (
n
43)
= · · ·
=i−1∑j=0
(3
4)jn+ 3iT (
n
4i)
18 Reurrence
On arrive a T (1) lorsquen
4i= 1, c-a-d lorsque i = log4(n). Ainsi,
T (n) = 4n(1− (3
4)log4(n)) + 3log4(n)T (1)
= 4n(1− (3
4)log4(n)) + nlog4(3)Θ(1) car 3log4(n) = nlog4(3)
= 4n+ Θ(nlog4(3)) pour n assez grand (3
4)log4(n) ≈ 0
Par consequent T (n) = O(n)
2.2.2 Methode de substitution
Cette methode recouvre deux phases :
— On conjecture la forme de la solution : c-a-d on devine (par intuition) une idee
de la solution.
— On utilise une recurrence mathematique pour trouver les constantes et pour mon-
trer que la solution est correcte.
— Le nom de cette methode vient du fait que l’on substitue la reponse
supposee a la fonction quand on applique l’hypothese de recurrence aux
valeurs plus petites.
— Elle ne s’applique que lorsque la forme de la reponse est facile a deviner.
Remarque 4.
Exemple 8.
T (n) = 2T (n
2) + n
On conjecture (par intuition) que la solution est T (n) = O(n log(n)).
La methode consiste a demontrer que T (n) ≤ cn log(n) pour un choix approprie de la
constante c > 0.
On suppose que T (n
2) ≤ cn
2log(
n
2).
La substitution donne
2.2 Resolution des recurrences 19
T (n) ≤ 2(cn
2log(
n
2)) + n
≤ cn log(n
2) + n
= cn log(n)− cn log(2) + n
= cn log(n)− cn+ n
≤ cn log(n) si c ≥ 1
Comment conjecturer les solutions des recurrences ?
— Malheureusement, il n’existe pas de regle generale.
— Deviner une bonne solution ressort de l’experience, c-a-d se servir des
recurrences deja rencontrees. Par exemple si T (n) = 2T (n2 + 100) + n.
Pour n assez grand, T (n2 ) et T (n2 + 100) sont quasiment les memes. On
peut donc supposer que T (n) = O(n log(n)).
— Parfois, il suffit d’une petite manipulation algebrique pour faire resembler
une recurrence inconnue a une autre deja vue. Par exemple, on utilise un
changement de variables.
Exemple : Prenons T (n) = 2T (√n) + log(n).
Posons m = log(n) ⇒ n = 2m. On aura donc T (2m) = 2T (2m2 ) +m.
On pose S(m) = T (2m), on obtient une nouvelle recurrence
S(m) = 2S(m
2) +m ⇒ S(m) = O(mlog(m)).
D’ou T (n) = T (2m) = S(m) = O(mlog(m)) = O(log(n) log(log(n))).
— Et parfois, de l’intuition pure ! ! !
Remarque 5.
Exemple & exercice : La recherche dichotomique
— Verifier que le nombre d’iteration de l’algorithme de recherche dichotomique d’un
tableau de taille n est
T (n) = T (n
2) + 1
20 Reurrence
— Montrer que
T (n) = O(log(n))
2.2.3 Methode generale
La methode generale est une methode qui s’appuie sur le theoreme maıtre de la
complexite, il est connu comme Master theorem en anglais et on l’appelle Theoreme
general en francais.
— Elle est consideree comme une ”recette” pour resoudre les recurrences de la forme
T (n) = aT (n
b) + f(n),
ou a ≥ 1 et b > 1 sont des constantes, et f(n) une fonction asymptotiquement
positive.
— Elle permet d’analyser le temps d’execution T (n) (au pire des cas) d’un algorithme
recursif obtenu par l’approche ”DIVISER-POUR-REGNER”.
2.2.4 DIVISER-POUR-REGNER
— L’approche ”diviser-pour-regner” est une technique pour la conception des algo-
rithmes.
— En effet, un algorithme base sur l’approche ”diviser-pour-regner”
1. separe le probleme en plusieurs sous-problemes semblables au probleme initial
mais de taille inferieure,
2. resolve les sous-problemes de facon recursive,
3. combine toutes les solutions pour produire la solution du probleme original.
— Le principe de l’approche ”diviser-pour-regner” se base sur trois etapes a chaque
niveau de recursivite :
1. Diviser le probleme en un certain nombre de sous-problemes.
2.3 Resolution des recurrences 21
2. Regner sur les sous-problemes en les resolvant recursivement.
Si la taille d’un sous-probleme est assez reduite, on peut le resoudre directe-
ment.
3. Combiner les solutions aux sous-problemes en une solution complete pour le
probleme initial.
Problème Solution
sous-problème 1
sous-problème 2
sous-problème j
sous-problème p diviser régner
solution 1
solution 1
solution 1
solution 1combiner
Problème Solution
sous-problème 1
sous-problème 2
sous-problème j
sous-problème p diviser régner
solution 1
solution 1
solution 1
solution 1combiner
2.3 Resolution des recurrences
— La recurrence de la forme T (n) = aT (nb ) + f(n), decrit le temps d’execution d’un
algorithme qui divise un probleme de taille n en a sous-problemes, chacun de taillen
b.
— Les a sous-problemes sont resolus recursivement, chacun dans un temps T (nb ).
— f(n) = D(n) + C(n) represente le cout induit par la decomposition du probleme
(D(n)) et la combinaison des resultats des sous-problemes (C(n)).
22 Reurrence
2.3.1 Theoreme general :
Soient a ≥ 1 et b > 1 deux constantes, soit f(n) une fonction et soit T (n) definie
pour les entiers n ≥ 0 par la recurrence
T (n) = aT (n
b) + f(n),
T (n) peut alors etre bornee asymptotiquement de la facon suivante.
1. Si ∃ε > 0 t.q. f(n) = O(nlogb(a)−ε) alors T (n) = Θ(nlogb(a)).
2. Si f(n) = Θ(nlogb(a)) alors T (n) = Θ(nlogb(a)log(n)).
3. Si ∃ε > 0 t.q. f(n) = Ω(nlogb(a)+ε) et si ∃c < 1 t.q. af(nb ) ≤ cf(n), pour
n suffisamment grand, alors T (n) = Θ(f(n)).
f(n) = Ω(g(n)) si ∃c > 0 t.q. pour n assez grand on ait 0 ≤ cg(n) ≤ f(n)
Theoreme 1.
2.3.1.1 Signification intuitive du theoreme
Dans chaque cas, on compare la fonction f(n) a la fonction nlogb(a). La solution de la
recurrence est determinee 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)).
Le theoreme general ne couvre pas toutes les possibilites pour f(n).
Remarque 6.
Exemple 9.
T (n) = 9T (n
3) + n
2.4 Exercices 23
Pour cette recurrence, on a a = 9, b = 3 et f(n) = n.
On a donc nlogb(a) = nlog3(9) = Θ(n2) et f(n) = n = O(nlog3(9)−ε), avec ε = 1.
D’apres le cas 1 du theoreme general, on peut dire que T (n) = Θ(n2).
Exemple 10.
T (n) = T (2n
3) + 1
Pour cette recurrence, on a a = 1, b = 32 et f(n) = 1.
On a donc nlogb(a) = n(log 3
2(1))
= n0 = 1. On est dans le cas 2 puisque f(n) =
Θ(nlogb(a)) = Θ(1).
La solution de la recurrence est donc T (n) = Θ(log(n)).
Exemple 11.
T (n) = 3T (n
4) + n log(n)
Pour cette recurrence, 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 ) = 3n4 log(n4 ) ≤ 3n
4 log(n) = c f(n) avec c = 34 < 1.
Par consequent, D’apres le cas 3, on peut dire que T (n) = Θ(n log(n)).
Exemple 12.
T (n) = 2T (n
2) + n log(n)
On a a = 2, b = 2 et f(n) = n log(n). On a donc nlogb(a) = nlog2(2) = n. Dans ce cas, le
theoreme general ne s’applique pas a la recurrence. En effet,
On pourrais penser que le cas 3 s’applique, puisque f(n) est plus grande asymptotique-
ment que nlogb(a) = n. Le probleme est que f(n)
nlogb(a)= log(n) est asymptotiquement plus
petit que nε, ∀ε > 0.
2.4 Exercices
Exercice 1 :
24 Reurrence
Pour chacune des fonctions suivantes, determiner le temps de calcul dans le pire des
cas et en O() en justifiant votre reponse :
1. int fonct1(int n) 2. int fonct2(int n)
int i,j,s=0; int i,j,s=n;
for(j=30;j>10;j--) for(i=200;i>100;i-=20)
for(i=n/2;i>0;i-=2) for(j=n;j>=n-4;j-=2)
s*=2; s/=2;
return s; return s;
3. int fonct3(int n) 4. int fonct4(int n)
int i,j=1,s=0; int i=0,j,s=0;
while(j<n) do
j=i++;
for(i=1;i<n*n;i*=2) while(j<2*i)
s++;
j++; s++;
j+=3;
return s;
while(i<n);
return s;
5. int fonct5(int n) 6. int fonct6(int n)
if(n==0) if(n==0)
return 1; return 1;
return 2*fonct5(n/4); return fonct6(n-1)+fonct6(n-1);
Exercice 2 :
1. Donner la complexite des algorithmes iteratifs suivants :
2.4 Exercices 25
(a) Ajouter un element en tete, fin et quelconque, d’une liste chaınee.
(b) Supprimer un element en tete, fin et quelconque, liste chaınee.
(c) Rechercher un element quelconque dans une liste chaınee.
2. Evaluer la complexite des methodes iteratives proposees pour
(a) calculer la puissance nieme d’un entier,
(b) trier (selection, bulle, insertion) un tableau (ou une liste),
(c) calculer le nieme terme de la suite de Fibonacci,
(d) effectuer la recherche dichotomique dans une table,
(e) parcourir un arbre binaire et rechercher un element dans un arbre binaire AVL.
Exercice 3 :
1. Donnez des bornes asymptotiques approchees pour T (n) dans chacun des recurrences
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.
2. Le temps d’execution d’un algorithme A1 resolvant un probleme P est decrit par
la recurrence T1(n) = 7T1(n2 ) + n2. Un autre algorithme A2 resolvant le meme
probleme P a un temps d’execution decrit par T2(n) = αT2(n4 ) +n2. Quelle est la
plus grande valeur de α telle que A2 soit asymptotiquement plus rapide que A1 ?
3. Soit une fonction definie par :
int fonct(int n)
if(n<2) return 1;
else return 4*fonct(n-1)-2*fonct(n-2);
26 Reurrence
(a) Soit T (n) le temps d’execution de la fonction fonct(). Exprimer T (n) en
fonction de T (n− 1) et T (n− 2).
(b) Calculer la complexite 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 meme traitement.
Exercice 5 :
1. Donner la complexite des algorithmes recursifs suivants :
(a) Supprimer un element quelconque dans une liste chaınee.
(b) Rechercher un element quelconque dans une liste chaınee.
(c) calculer la puissance nieme d’un entier,
(d) trier (fusion, rapide, tas) un tableau (ou une liste),
(e) calculer le nieme terme de la suite de Fibonacci,
(f) effectuer la recherche dichotomique dans une table.
2. Evaluer la complexite des differents algorithmes recursifs, vus au cours et en TD,
traitant les arbres binaires.
Exercice 4 :
Le tri fusion est une methode algorithmique basee sur la technique ”diviser pour
regner”. Le principe de cette methode peut etre decrit par l’algorithme recursif suivant :
— On divise la liste en deux parties presque de meme tailles,
— On trie les deux parties,
— On fusionne les deux parties.
Ce processus de la recursivite s’arrete une fois la decomposition des sous-listes donnent
des sous-listes composees d’un seul element et le tri est alors trivial.
1. Ecrire une fonction de prototype liste diviseListe(liste l) qui permet de
diviser une liste chaınee en deux sous-liste. Calculer sa complexite en fonction de
la taille de la liste d’entree.
2.4 Exercices 27
2. Ecrire une fonction de prototype liste FusionListe(liste lG,liste lD) qui
permet de fusionner deux listes. Calculer sa complexite.
3. Ecrire une fonction de prototype void triFusionListe(liste *l) qui permet
de trier une liste chaınee d’entiers. Calculer sa complexite en fonction de la taille
de la liste d’entree.