Chapitre 1
Chapitre 1
Chapitre 1
Complexité algorithmique
Supports de cours vol.1 – Période 2005-2014
17 Complexité algorithmique
Comme on l’a vu lors de l’implémentation des types abstraits, il est souvent possible
d’implémenter plusieurs solutions à un problème donné. La question se pose alors de savoir
quel algorithme est le plus efficace. Et pour effectuer cette comparaison, il est nécessaire de
déterminer sur quels critères elle doit être effectuée. Le but de cette section est d’introduire le
champ de la théorie de la complexité, dont l’un des buts est de répondre à ce type de question.
Le problème de cette démarche est qu’elle ne permet pas de comparer les algorithmes de
manière objective, car ils ne sont pas les seuls facteurs intervenant dans la performance de
résolution du problème : d’autres facteurs extérieurs interviennent également (matériel,
logiciel...).
La solution retenue est de se détacher de ses facteurs extérieurs, et donc de l’implémentation
de l’algorithme. Pour cela, nous allons utiliser une approche plus théorique, reposant sur deux
notions : les opérations élémentaires et les positions mémoire.
Opération élémentaire : opération atomique, correspondant à une instruction assembleur.
Rappelons qu’une instruction assembleur est atomique, dans le sens où elle correspond à un
code directement interprétable par le processeur. Autrement dit, une instruction assembleur est
associée à une action que le processeur peut réaliser, comme par exemple placer une certaine
valeur dans à une certaine adresse en mémoire. Par comparaison, une instruction du langage C
se décompose généralement en plusieurs instructions assembleur.
La notion d’opération élémentaire va être utilisée pour représenter la consommation que
l’algorithme analysé effectue en termes de temps de calcul. On dira par exemple qu’il a besoin
d’effectuer 𝑥 opérations élémentaires pour résoudre le problème traité.
Position mémoire : unité de mémoire élémentaire, correspondant généralement à un octet.
La notion de position mémoire est une abstraction de l’occupation qu’un algorithme a de la
mémoire. Elle va nous permettre d’évaluer cette consommation de façon indépendante de
178/232
Supports de cours vol.1 – Période 2005-2014
Ces deux notions nous permettent d’exprimer la complexité d’un algorithme en fonction de
la taille des données qu’il traite.
Taille des données d’un problème : entier(s) représentant la grandeur des paramètres reçus
par l’algorithme devant résoudre le problème.
Notez bien que la taille peut n’être représentée par un seul entier, mais aussi par plusieurs
entiers distincts. Leur nombre et leur signification exacte dépendent fortement de la nature du
problème étudié :
Nombre d’éléments à traiter ;
Grandeur des éléments à traiter ;
etc.
exemples :
Tri d’un tableau de taille 𝑁 : la taille des donnés est 𝑁, le nombre d’éléments du
tableau.
Calcul de 𝐶𝑛𝑝 : la taille des données est le couple 𝑛, 𝑝 .
L’idée est que si la taille est petite, le problème sera vraisemblablement plus facile à
résoudre que si elle est énorme. On veut généralement savoir comment la complexité de
l’algorithme évolue quand on fait grandir la taille du problème.
Complexité d’un algorithme : nombre d’opérations élémentaires ou de positions mémoire
dont l’algorithme a besoin pour résoudre un problème d’une certaine taille.
179/232
Supports de cours vol.1 – Période 2005-2014
exemple : 2 fonctions différentes calculant le produit des nombres d’un tableau d’entiers.
int produit1(int tab[N])
1 { int i;
2 int resultat=1;
3 for(i=0;i<N;i++)
4 resultat = resultat*tab[i];
5 return resultat;
}
o Première fonction :
2 : affectation de resultat (d).
3 : affectation de i (d).
Dans le for :
3 : comparaison i<N (c) et incrémentation de i (une addition
(b) et une affectation (d)).
4 : opération * (a) et affectation à resultat (d).
Nombre de répétitions du for : N
3 : comparaison du for à la sortie de la boucle (c).
Retour de la valeur resultat (e).
On a : 𝑑 + 𝑑 + 𝑁 𝑐 + 𝑏 + 𝑑 + 𝑎 + 𝑑 + 𝑐 + 𝑒 = 2𝑑 + 𝑁 𝑎 + 𝑏 +
𝑐 + 2𝑑 + 𝑐 + 𝑒
Total : 𝑇1 𝑁 = 𝑁𝑎 + 𝑁𝑏 + 𝑁 + 1 𝑐 + 𝑁 + 1 2𝑑 + 𝑒
o Seconde fonction :
1 : affectation de i (d).
2 : affectation de resultat (d).
Dans le while :
3 : comparaisons resultat!=0 (c) et i<N (c), opération &&
(f).
4 : opération * (a) et affectation à resultat (d).
180/232
Supports de cours vol.1 – Période 2005-2014
5
: incrémentation de i (une addition (b) et une affectation
(d)).
Nombre de répétitions du while :
M si le tableau contient un zéro en (𝑀 − 1)ème position.
N si le tableau ne contient pas de zéro.
3 : comparaisons du while à la sortie de la boucle :
1 comparaison resultat!=0 (c) si le tableau contient un
zéro.
2 comparaisons (c) et un && (f) si le tableau ne contient pas
de zéro.
Retour de la valeur resultat (e).
on a :
𝑑 + 𝑑 + 𝑀 𝑐 + 𝑓 + 𝑐 + 𝑎 + 𝑑 + 𝑏 + 𝑑 + 𝑐 + 𝑒 = 2𝑑 +
𝑀 𝑎 + 𝑏 + 2𝑐 + 2𝑑 + 𝑓 + 𝑐 + 𝑒
𝑑+𝑑+𝑁 𝑐+𝑓+𝑐+𝑎+𝑑+𝑏+𝑑 +𝑐+𝑓+𝑐+𝑒 =
2𝑑 + 𝑁 𝑎 + 𝑏 + 2𝑐 + 2𝑑 + 𝑓 + 2𝑐 + 𝑓 + 𝑒
Total :
𝑀𝑎 + 𝑀𝑏 + 2𝑀 + 1 𝑐 + 𝑀 + 1 2𝑑 + 𝑒 + 𝑀𝑓 𝑠𝑖 ∃𝑀: 𝑡𝑎𝑏[𝑀 − 1] = 0
𝑇2 𝑁 = {
𝑁𝑎 + 𝑁𝑏 + 2 𝑁 + 1 𝑐 + 𝑁 + 1 2𝑑 + 𝑒 + 𝑁 + 1 𝑓 𝑠𝑖𝑛𝑜𝑛
Remarque : il existe un lien entre les complexités spatiale et temporelle d’un algorithme.
D’abord, sur une machine mono-processeur (i.e. ne possédant qu’un seul processeur, et donc
capable d’exécuter une seule instruction à la fois), la complexité spatiale ne peut pas dépasser
la complexité temporelle, puisqu’il faut effectuer au moins une opération pour initialiser une
position mémoire.
De plus, il est souvent possible de faire diminuer la complexité temporelle en augmentant
la complexité spatiale, et vice-versa. Par exemple, supposons qu’on réalise le calcul d’une
quantité 𝑥 = 𝑓(ℎ 𝑥 ) + 𝑔(ℎ 𝑥 ), où. Supposons que h est une fonction difficile à calculer. On
peut voir deux possibilités ici :
o Soit on calcule ℎ 𝑥 deux fois, et cela risque de prendre longtemps ;
o Soit on définit une variable 𝑦 = ℎ 𝑥 , ce qui augmente l’occupation mémoire, mais
diminue le temps de calcul.
181/232
Supports de cours vol.1 – Période 2005-2014
182/232
Supports de cours vol.1 – Période 2005-2014
Il s’agit de la complexité que l’on rencontre le plus souvent dans la littérature quand on veut
décrire un algorithme. En effet, même si le cas défavorable est susceptible d’être rare, à l’instar
du cas favorable, en revanche il est plus discriminant. Il est aussi plus pertinent d’obtenir une
borne supérieure du temps d’exécution ou de l’occupation mémoire.
Complexité moyenne : complexité de l’algorithme moyennée sur l’ensemble de toutes les
données possibles.
On peut considérer que c’est la complexité la plus représentative de l’algorithme.
Cependant, elle est généralement difficile à calculer, et on ne la rencontre donc pas
fréquemment.
Rappelons d’abord formellement ces notations, avant de montrer comment elles peuvent
être utilisées dans le cadre de la complexité algorithme. Soient 𝑓 et 𝑔 deux fonctions définies
de ℕ dans ℕ :
183/232
Supports de cours vol.1 – Période 2005-2014
o 𝑔3 𝑥 = 43 = 64.
𝑓∈Ω 𝑔1 : prenons 𝑎 = 1 et 𝑥0 = 1 :
o 𝑓 𝑥 = 3 × 12 + 1 = 4.
o 𝑔1 𝑥 = 4 × 1 = 4.
𝑓∈Ω 𝑔2 : prenons 𝑎 = 1 et 𝑥0 = 2 :
o 𝑓 𝑥 = 3 × 22 + 1 = 13.
o 𝑔2 𝑥 = 22 + 4 = 8.
𝑓∈Θ 𝑔2 car 𝑓 ∈ Ω 𝑔2 et 𝑓 ∈ 𝑂 𝑔2 .
En pratique, pour obtenir la borne asymptotique supérieure une fois qu’on a exprimé 𝑓 sous
la forme d’un polynôme, il suffit de ne conserver que le terme de degré le plus élevé, et
d’ignorer les coefficients constants.
exemple : 2𝑥 2 + 3𝑥 + 1 = 𝑂 2𝑥 2 + 𝑂 3𝑥 + 𝑂 1 = 𝑂 2𝑥 2 = 𝑂 𝑥 2
184/232
Supports de cours vol.1 – Période 2005-2014
produit1
produit2
𝑵 Algorithme 𝑨 Algorithme 𝑩
10 1000 200
100 10000 20000
1000 100000 2000000
10000 1000000 200000000
algo.A
algo.B
Pour des valeurs de 𝑁 inférieures à 50, on peut observer que 𝐵 est plus rapide que 𝐴. Au-
dessus de 50, 𝐴 est largement plus performant, et la différence ne cesse de s’accroître.
185/232
Supports de cours vol.1 – Période 2005-2014
Asymptotiquement, la complexité de 𝐴 (qui est en 𝑂 𝑁 ) est plus faible que celle de 𝐵 (qui est
en 𝑂 𝑁 2 ).
exemple : recherche du plus petit élément dans un tableau non trié de taille 𝑁.
int cherche_minimum (int tab[N])
{ int i;
1 int indice=0; 𝑂 1
2 for(i=1;i<N;i++) 𝑂 1
𝑂 𝑁
3 if(tab[i] < tab[indice]) 𝑂 1 𝑂 𝑁
4 indice = i; 𝑂 1
5 return tab[indice]; 𝑂 1
}
ligne 1 : affectation : 𝑂 1 .
dans le for :
186/232
Supports de cours vol.1 – Période 2005-2014
o affectation : 𝑂 1 .
o comparaison i<N : 𝑂 1 .
o incrémentation i++ : 𝑂 1 .
o dans le if :
test : 𝑂 1 .
affectation : 𝑂 1 .
total : le if a une complexité de : 𝑂 1 + 𝑂 1 = 𝑂 1 .
o total :
le for est répété 𝑁 − 1 fois.
complexité : 𝑂 1 + 𝑁(𝑂 1 + 𝑂 1 + 𝑂 1 ) = 𝑂 𝑁 .
retour de valeur : 𝑂 1 .
total : 𝑂 1 + 𝑂 𝑁 + 𝑂 1 = 𝑂 𝑁 .
exemple : recherche du plus petit élément dans un tableau non trié de taille 𝑁.
Tableau : 𝑂 𝑁 .
Variables simples i et indice : 𝑂 1 + 𝑂 1 = 𝑂 1 .
17.2.3 Exercices
187/232
Supports de cours vol.1 – Période 2005-2014
10 return continuer; 𝑂 1
}
Complexité temporelle :
lignes 1 et 2 : affectations : 𝑂 1
ligne 3 : dans le while :
o test : 𝑂 1
o lignes 4 et 5 : séquence d’opérations élémentaires 𝑂 1
o dans le while :
test : 𝑂 1
lignes 7 et 8 : séquence d’opérations élémentaires 𝑂 1
total :
nombre de répétitions : quel est le pire des cas ?
o le tableau est une permutation
o j=1 à N-1, soit N-1 répétitions
complexité : 𝑁 − 1 𝑂 1 = 𝑂 𝑁
o ligne 9 : opérations élémentaires : 𝑂 1
o total :
nombre de répétitions : quel est le pire des cas ?
le tableau est une permutation.
𝑖 = 0 à 𝑁 − 1, soit 𝑁 répétitions.
complexité : 𝑁 ∙ 𝑂 1 + 𝑁 = 𝑂 𝑁 2
ligne 10 : opération élémentaire : 𝑂 1
total : 𝑂 1 + 𝑂 𝑁 2 + 𝑂 1 = 𝑂 𝑁 2
Complexité spatiale :
on manipule exclusivement des entiers, donc on évaluera la complexité spatiale en
termes de nombre de positions mémoire d’entiers.
1 tableau tab de taille N : 𝑂 𝑁
3 variables i, j et continuer : 3 × 𝑂 1
total : 𝑂 𝑁 + 3 × 𝑂 1 = 𝑂 𝑁
188/232
Supports de cours vol.1 – Période 2005-2014
13 return continuer; 𝑂 1
}
Complexité temporelle :
lignes 1 et 2 : affectations : 𝑂 1
dans le while :
o test : 𝑂 1
o lignes 5, 6 et 7 : opérations élémentaires : 𝑂 1
o total :
nombre de répétitions au pire des cas : N
complexité : 𝑁 × 𝑂 1 = 𝑂 𝑁
ligne 8 : affectation : 𝑂 1
dans le while :
o test : 𝑂 1
o lignes 10, 11 et 12 : opérations élémentaires : 𝑂 1
o total :
nombre de répétitions au pire des cas : 𝑁
complexité : 𝑁 × 𝑂 1 = 𝑂 𝑁
ligne 13 : opération élémentaire : 𝑂 1
total : 𝑂 1 + 𝑂 𝑁 + 𝑂 𝑁 + 𝑂 1 = 𝑂 𝑁
Complexité spatiale :
2 tableaux tab et teste de taille N : 𝑂 𝑁
2 variables simples i et continuer : 2 × 𝑂 1
total : 𝑂 𝑁 + 2 × 𝑂 1 = 𝑂 𝑁
Remarques :
o la complexité spatiale a-t-elle augmenté ? Oui : elle passe de 3 + 𝑁 à 2 +
2𝑁.
o Cela a-t-il une importance asymptotiquement parlant ? Non : la complexité
asymptotique reste en 𝑂 𝑁 .
189/232
Supports de cours vol.1 – Période 2005-2014
Complexité temporelle :
lignes 1 et 2 : affectations : 𝑂 1
dans le while :
o test : 𝑂 1
o dans le if :
test : 𝑂 1
premier bloc :
ligne 5 : opération élémentaire : 𝑂 1
else :
ligne 6 : opération élémentaire : 𝑂 1
total : 𝑂 1 + max(𝑂 1 , 𝑂 1 ) = 𝑂 1
o total :
nombre de répétitions au pire des cas : N
complexité : 𝑁 × 𝑂 1 = 𝑂 𝑁 .
ligne 7 : opération élémentaire : 𝑂 1 .
total : 𝑂 1 + 𝑂 𝑁 + 𝑂 1 = 𝑂 𝑁 .
Complexité spatiale :
1 tableau tab de taille N : 𝑂 𝑁
3 variables simples i, trouve et v : 3 × 𝑂 1
total : 𝑂 𝑁 + 3 × 𝑂 1 = 𝑂 𝑁
190/232
Supports de cours vol.1 – Période 2005-2014
Complexité temporelle :
lignes 1, 2 et 3 : affectations : 𝑂 1
dans le while :
o test : 𝑂 1
o dans le if :
test : 𝑂 1
dans le if :
test : 𝑂 1
premier bloc :
o ligne 8 : opération élémentaire : 𝑂 1
else :
o ligne 9 : opération élémentaire : 𝑂 1
total : 𝑂 1 + max(𝑂 1 , 𝑂 1 ) = 𝑂 1
ligne 10 : opération élémentaire : 𝑂 1
total : 𝑂 1 + 𝑂 1 + 𝑂 1 = +𝑂 1
o total :
nombre de répétitions au pire des cas :
le while est répété tant qu’on n’a pas trouvé l’élément et que la
recherche est possible.
le pire des cas est celui où on ne trouve pas l’élément : il faut
poursuivre la recherche jusqu’à ce que ce ne soit plus possible.
à chaque itération, on coupe en deux l’intervalle exploré (ligne 5 :
m = (a+b)/2;)
dans le pire des cas, on va donc couper l’intervalle en deux
jusqu’à obtenir un intervalle ne pouvant plus être divisé
(intervalle ne contenant qu’un seul élément).
la question est donc : combien de fois peut-on couper N en deux ?
supposons qu’on puisse couper N en deux p fois. On a alors : 𝑁 =
2𝑝 + 𝑘, avec 𝑘 ∈ ℕ.
par définition du logarithme : 𝑝 ≤ log 2 𝑁.
On en déduit que l’intervalle de taille N peut être coupé au plus
⌊log 2 𝑁⌋ + 1 fois.
complexité : ⌊log 2 𝑁⌋ + 1 × (𝑂 1 + 𝑂 1 ) = 𝑂 log 𝑁 .
ligne 11 : opération élémentaire : 𝑂 1 .
191/232
Supports de cours vol.1 – Période 2005-2014
Complexité spatiale :
1 tableau tab de taille N : 𝑂 𝑁
4 variables simples a, b, m et v : 4 × 𝑂 1
17.3.1 Généralités
On a vu en section 13.3 que le traitement récursif peut être décrit par un arbre d’appels, qui
représente les relations entre les différents appels récursifs effectués au cours du traitement.
Tout en haut de l’arbre, sa racine correspond au tout premier appel effectué. Le temps nécessaire
à la résolution du problème traité correspond au temps nécessaire pour exécuter cet appel. Or,
il y a deux types de traitements dans cet appel : une partie est locale, et l’autre est récursive, i.e.
elle est effectuée au moyen d’appels supplémentaires. Le temps d’exécution de l’appel initial
correspond donc à la somme du temps utilisé pour le traitement local, et du temps utilisé pour
les appels récursifs. Le même principe s’applique pour chacun de ces appels récursifs. Au final,
il vient que le temps total est égal à la somme des temps de traitement local pour tous les appels
effectués.
En termes de complexité temporelle, cela signifie que la complexité temporelle de l’appel
considéré est égale à la somme des complexités temporelles associées aux traitements locaux
des appels effectués. Considérons par exemple un appel récursif simple, qui prend la forme
d’un arbre linéaire du type suivant :
Alors la complexité temporelle de l’appel initial est calculée à partir des nœuds grisés (c’est-
à-dire tous les nœuds). Si la récursivité multiple, on obtient un arbre non-linéaire du type
suivant :
Là encore, on doit considérer tous les nœuds présents dans l’arbre, puisque ils doivent tous
être traités avant que le calcul ne se termine (un appel initial ne peut pas s’achever avant que
tous ses propres appels soient eux-mêmes terminés).
Pour la mémoire, la situation est un peu différente, car son occupation peut croître ou
décroître avec l’évolution de l’exécution (alors que le temps de calcul ne peut que croître). On
sait que la complexité spatiale correspond à l’occupation maximale atteinte lors de l’exécution
de l’algorithme étudié. Pour reprendre l’image de l’arbre d’appel, cela signifie qu’on cherche
le nœud tel que la somme des occupations spatiales de tous ses ancêtres est maximale.
Autrement dit, on fait la somme des occupations spatiales pour la pire branche de l’arbre.
192/232
Supports de cours vol.1 – Période 2005-2014
Pour le cas de la récursivité simple, cela signifie généralement qu’on fait la somme des
occupations mémoires pour chaque appel.
Attention toutefois, ce n’est pas forcément toujours vrai. Par exemple, si la fonction utilise
l’allocation dynamique, il est possible qu’elle libère de la mémoire avant l’appel ou qu’elle
l’alloue après l’appel. Dans ce cas-là, on peut avoir une complexité spatiale ponctuellement
élevée mais qui ne s’applique pas récursivement.
Par exemple, supposons que la fonction déclare 1 entier statique et un tableau de 1000
entiers dynamique. À ce moment-là, on a donc 1001 entiers en mémoire. Puis, la fonction libère
ces 1000 entiers avant de faire l’appel récursif. Le deuxième appel va faire la même chose, ce
qui signifie qu’à un moment donné, on occupera en mémoire l’espace nécessaire au stockage
de 1002 entiers (et non pas 2002). À moins de répéter l’appel récursif un grand nombre de
fois, on restera largement en dessous de la taille du tableau.
Pour la récursivité multiple, on a un arbre non-linéaire de la forme suivante :
Ici, la différence avec la complexité temporelle est encore plus nette. À un moment donné
de l’exécution, on ne doit considérer qu’un seul nœud et tous ces ancêtres (i.e. les nœuds
permettant de remonter jusqu’à la racine). Comme on s’intéresse à l’occupation maximale, on
doit déterminer quelle est la pire des branches, comme ici celle représentée en gris. La
complexité spatiale est alors la somme des complexités individuelles de chaque nœud présent
sur cette branche.
En raison de l’aspect récursif des algorithmes étudiés, on a ici besoin d’une relation de
récurrence pour exprimer ces complexités. Pour rappel, une récurrence est une équation ou une
inégalité décrivant une fonction à partir de sa valeur pour des paramètres différents
(généralement : plus petits).
Soit 𝑇 𝑛 la complexité temporelle de la fonction pour une taille 𝑛 des données d’entrée. Si
on considère un cas d’arrêt, 𝑇 𝑛 correspond à la complexité du traitement effectué pour ce cas.
Sinon, dans le cas général, 𝑇 𝑛 dépend de :
La complexité 𝑓 𝑛 du traitement effectué localement à la fonction ;
La complexité de l’appel récursif 𝑇(ℎ 𝑛 ), avec ℎ 𝑛 ≠ 𝑛.
Remarque : le plus souvent, ℎ 𝑛 est de la forme ℎ 𝑛 = 𝑛 − 𝑘 ou ℎ 𝑛 = 𝑛/𝑘, k étant
une constante.
Complexité temporelle :
Complexité du cas d’arrêt 𝑛 = 1 :
193/232
Supports de cours vol.1 – Période 2005-2014
o ligne 1 : condition du if : 𝑂 1
o ligne 2 : affectation : 𝑂 1
o ligne 4 : opération élémentaire : 𝑂 1
o total : 𝑇 𝑛 = 𝑂 1 + 𝑂 1 + 𝑂 1 = 𝑂 1 .
Complexité du cas général 𝑛 > 1 :
o ligne 1 : condition du if : 𝑂 1
o ligne 3 :
multiplication : 𝑂 1
appel récursif : 𝑇 𝑛 − 1
o ligne 4 : opération élémentaire : 𝑂 1
o total : 𝑇 𝑛 = 𝑂 1 + 𝑂 1 + 𝑇 𝑛 − 1 + 𝑂 1 = 𝑂 1 + 𝑇 𝑛 − 1 .
o remarque : ici ℎ 𝑛 = 𝑛 − 1.
Complexité spatiale :
complexité du cas d’arrêt 𝑛 = 1 :
o deux variables entières n et résultat
o total : 𝑆 𝑛 = 𝑂 1
complexité du cas général 𝑛 > 1 :
o deux variables entières n et résultat
o les variables utilisées dans l’appel récursif : 𝑆 𝑛 − 1
o total : 𝑆 𝑛 = 𝑂 1 + 𝑆 𝑛 − 1
Une fois que la récurrence est établie, il faut la résoudre pour obtenir la complexité de
l’algorithme. En d’autres termes, on doit exprimer la fonction 𝑇 𝑛 sans utiliser 𝑇. Il existe de
nombreuses méthodes pour résoudre une récurrence. Dans le cadre de ce cours, nous limiterons
aux suivantes :
Méthode par substitution ;
Méthode par bornage ;
Méthode par arbre.
194/232
Supports de cours vol.1 – Période 2005-2014
On recommence :
𝑇 𝑛 = 2𝑏 + (𝒃 + 𝑻 𝒏 − 𝟑 ) = 3𝑏 + 𝑇 𝑛 − 3 (4)
𝑇 𝑛 = 3𝑏 + (𝒃 + 𝑻 𝒏 − 𝟒 ) = 4𝑏 + 𝑇 𝑛 − 4 (5)
etc.
On peut faire l’hypothèse qu’on s’intéresse à la propriété 𝑃𝑖 telle que : 𝑇 𝑛 = i𝑏 +
𝑇 𝑛 − i pour 1 < 𝑖 < 𝑛.
3. Prouvons 𝑃𝑖 :
o Cas de base : 𝑖 = 1
Le cas de base correspond à notre définition de la complexité :
𝑇 𝑛 = 1𝑏 + 𝑇 𝑛 − 1 (𝑃1 )
o Cas de récurrence : 2 < 𝑖 < 𝑛
On suppose que Pi est vraie, et on veut prouver Pi+1 :
𝑇 𝑛 = 𝑖𝑏 + 𝑇 𝑛 − 𝑖 (𝑃𝑖 )
Or on a par définition de 𝑇 :
𝑇 𝑛−𝑖 =𝑏+ 𝑇 𝑛−𝑖−1
On remplace 𝑇 𝑛 − 𝑖 dans Pi :
𝑇 𝑛 = 𝑖𝑏 + (𝑏 + 𝑇 𝑛 − 𝑖 − 1 )
𝑇 𝑛 = 𝑖 + 1 𝑏 + 𝑇(𝑛 − 𝑖 + 1 ) (𝑃𝑖+1 )
o On a prouvé P.
4. On peut donc maintenant se ramener à une expression de 𝑇 𝑛 en posant 𝑖 = 𝑛 −
1:
𝑇 𝑛 = 𝑛 − 1 𝑏 + 𝑇(𝑛 − 𝑛 − 1 )
𝑇 𝑛 = 𝑛−1 𝑏+ 𝑎
o Au final, la complexité temporelle est donc 𝑇 𝑛 = 𝑂 𝑛 + 𝑂 1 = 𝑂 𝑛
Remarque : la complexité spatiale est identique, puisqu’elle repose sur la même définition
récursive.
195/232
Supports de cours vol.1 – Période 2005-2014
Remarque : avec cette méthode, on peut prouver que la complexité d’une fonction est en
𝑂 𝑔 , mais on ne prouve pas qu’il n’existe pas de meilleure borne supérieure (i.e. une borne
d’ordre inférieur). Cependant, on peut l’utiliser pour trouver une borne supérieure et une borne
inférieure de même forme (on a donc une borne approchée).
1 if(debut<=fin) 𝑂 1
2 { m = (debut+fin)/2; 𝑂 1
3 if(tab[m]==v) 𝑂 1
4 resultat = 1; 𝑂 1
else
5 { if(tab[m]>v) 𝑂 1
6 resultat = recherche_dicho(tab, debut, m-1, v); 𝑇 𝑁/2 + O 1
else
7 resultat = recherche_dicho(tab, m+1, fin, v); 𝑇 𝑁/2 + O 1
}
}
else
8 resultat = 0; 𝑂 1
9 return resultat; 𝑂 1
}
196/232
Supports de cours vol.1 – Période 2005-2014
197/232
Supports de cours vol.1 – Période 2005-2014
200/232