Vous êtes sur la page 1sur 101

Université Mohammed Premier

Ecole Nationale des Sciences Appliquées


Al Hoceima

Algorithmique avancée et complexité

E.W. DADI
wrd.dadi@gmail.com
Année universitaire : 2014/2015
Plan du Cours
Chapitre 1: Introduction à l’algorithmique
Chapitre 2: Complexité algorithmique
Chapitre 3: Etude de quelques algorithmes
Chapitre 4: Programmation dynamique
Chapitre 5: Calcul Haute Performance

ENSAH Introduction générale E.W. DADI – page : 2


Références :
Thomas Cormen, Charles Leiserson, Ronald Rivest, Clifford
Stein, « INTRODUCTION À L’ALGORITHMIQUE »,
Dunod, Paris, 2004.
Rémy Malgouyres, Rita Zrour, Fabien Feschet, « INITIATION
À L’ALGORITHMIQUE ET À LA PROGRAMMATION EN
C », Dunod, Paris, 2008, 2011
Bruno Baynat, «EXERCICES ET PROBLEMES
D’ALGORITHMIQUE », Dunod, Paris.
Donald E. Knuth « THE ART OF COMPUTING
PROGRAMMING »
Des supports de cours sur le Web

ENSAH Introduction générale E.W. DADI – page : 3


Objectifs du cours

Acquérir les notions nécessaires pour :


analyser et classer les problèmes de
différents domaines.
construire la ou les solutions.
évaluer les différentes solutions en terme de
temps du calcul.
Choisir la meilleure solution.

ENSAH Introduction générale E.W. DADI – page : 4


Utilisation des algorithmes
Plusieurs domaines et applications reposent sur des algorithmes intelligents
qui permettent de gérer et manipuler de grosses masses de données, à
savoir :
L’accès rapide à toutes sortes de données sur Internet.
Réseau Informatique: Recherche de routes optimales pour
l’acheminement des données; Un nœud de routage Internet peut
avoir à déterminer le chemin le plus court à travers le réseau pour
minimiser le délai d’acheminement d’un message.
Moteur de recherche: utilisation d’un moteur de recherche pour
trouver rapidement les pages contenant tel ou tel type de données;
Sécurité Informatique: Le commerce électronique permet de négocier
et échanger, de manière électronique, biens et services. Les clients
exigent la confidentialité de données telles que numéros de carte de
crédit, mots de passe et relevés bancaires. La cryptographie et les
signatures numériques qui font partie des technologies fondamentales
employées dans ce contexte, s’appuient sur des algorithmes numériques
et sur la théorie des nombres.
etc..

ENSAH Introduction générale E.W. DADI – page : 5


Pour quoi chercher des algorithmes efficaces?
Le temps machine est une ressource limitée, et il en est de
même de l’espace mémoire. La loi de Moore attient ses limites
(G. Moore a prévu un doublement du nombre de transistors
tous les 24 mois). L'augmentation de la puissance de calcul en
élevant la fréquence du processeur s’est heurtée à plusieurs
problèmes généralement liées à la surchauffe.
Les contraintes économiques obligent à toujours produire dans
l'urgence. Les entreprises cherchent toujours à maximiser leur
profit. Il existe beaucoup de solutions à priori, mais la plupart
d’entre elles ne sont pas celles que nous voulons. Trouver une
solution qui convienne vraiment, n’est pas toujours évident.

ENSAH Introduction générale E.W. DADI – page : 6


…. la suite
Problèmes nécessitant un grande temps d’exécution
L'exploration de grande volume de données(Big Data)
Les prédictions météorologique
La modélisation et simulation de problèmes de dimensions plus
grandes, la modélisation et la simulation sur ordinateur ont pour
objet de créer une représentation virtuelle d’un objet, d’un
phénomène ou d’un concept afin de l’analyser et de le
comprendre, de façon à pouvoir prévoir son comportement, voire
le contrôler.
l’étude de systèmes et de phénomènes complexes. Elle repose
désormais sur la gestion et l'utilisation d’une masse
d’information qu’il faut systématiser, recueillir, distribuer et
exploiter
l'intelligence artificielle
Le décryptage de messages et la recherche de mots de passe

ENSAH Introduction générale E.W. DADI – page : 7


Chapitre 1: Introduction à
l’algorithmique
Plan du chapitre
I. Notion d’algorithme
II. Un langage pour décrire les algorithmes
III. Algorithmes itératifs et récursifs
IV. Preuve d’un algorithme

ENSAH Introduction à l’algorithmique E.W. DADI – page : 9


I. Notion d’algorithme
1. Qu'est-ce qu'un algorithme ?
Un algorithme est une suite finie d’opérations élémentaires constituant
un schéma de calcul ou de résolution d’un problème.
La résolution d’un problème algorithmique par un algorithme commence
par la spécification des données en entrée (Input) et des données en sortie
(Output).
Données en entrée: l'ensemble complet des instances (Input) de
l’algorithme sur lesquelles il va travailler;
Données en sortie : Sa production (Output) après son exécution sur
une de ces instances.
Exemple: Le problème algorithmique connu sous le nom du problème de
tri est défini comme suit :
Problème : le tri.
Input : une liste de n clés <a1, …, an>.
Output : une permutation de la liste d'entrée <a1', …, an'> qui soit
ordonnée : a1'  …  an'.
Une instance du problème de tri pourrait être :
Une liste de numéros comme <14, 25, 58, 34, 64, 34>;
Une liste de noms comme <nom1, nom2, nom3, nom4>;

ENSAH Introduction à l’algorithmique E.W. DADI – page : 10


2. Pluralité des solutions algorithmiques
Pour un même problème algorithmique, il peut exister
plusieurs algorithmes différents :
Certains itératifs, d’autres récursifs;
Certains sont plus rapides que les autres;
Certains utilisent moins d’espace mémoire que d’autres;
…etc.
Par exemple pour trier un tableau il y a beaucoup
d’algorithmes différents : tri par sélection, tri par insertion,
tri à bulles, tri par fusion, tri rapide, tri par tas, …etc.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 11


3. Propriétés d’un bon algorithme
Il y a trois propriétés désirables pour un bon
algorithme :
Correction;
Efficacité;
Facilité à mettre en œuvre;
Ces trois objectifs ne peuvent pas toujours être tous
atteints simultanément.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 12


II. Un langage pour décrire les algorithmes
1. Structure générale d’un algorithme
Pour la définition d'un problème on utilise un langage
scientifique.
Pour des raisons de simplicité, on utilise une langue
naturelle(le français par exemple)
Algorithme
Fonction Nom_Fonction(Input) : Output
Var … // variables
Début
… // actions
Fin

ENSAH Introduction à l’algorithmique E.W. DADI – page : 13


2. Les différents éléments d’un algorithme

Type de données Opérations de base


 Entier;  +-*/%
 Réel;  , , , , = et 
 Caractère;  Non, Et, Ou
 Chaînes de caractères;  := (affectation)
 Booléen (vrai / faux);  Afficher
 Tableau;  Lire

Structures de contrôle
 Si … Alors … Sinon … FinSi
 Pour … Faire … FinPour
 Tant Que … Faire … FinTQ
 Répéter … Jusqu’à … FinRép
 Retourner …

ENSAH Introduction à l’algorithmique E.W. DADI – page : 14


III. Algorithmes itératifs et récursifs
1. Algorithmes itératifs
Un algorithme itératif résout un problème en calculant son
résultat par une méthode d’approximation successive.
Ses composants sont :
Initialisation : préciser la valeur adéquate de départ.
Approximation : décrire la manière de s’approcher du
résultat.
Progression : indiquer la façon d’aller d’une étape à une
autre.
Les boucles sont un moyen pour décrire un algorithme
itératif.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 15


2. Algorithmes récursifs
Un algorithme récursif est constitué d’une fonction récursive.
Une fonction est dite récursive si elle s’appelle elle-même.
L’appel d’une fonction à l’intérieur d’elle-même est nommé
appel récursif.
Un appel récursif doit obligatoirement être dans une
instruction conditionnelle (sinon la récursivité est sans fin).
Ses composants sont :
Cas de base (condition d’arrêt) : le problème peut se
résoudre d’une manière directe. La donnée est
suffisamment petite pour qu’elle puisse traitée de façon
simple.
Appel récursif (récurrence) : le problème se résout en
utilisant un algorithme identique mais sur une donnée plus
petite.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 16


…. la suite
Exemple 1 : un exemple concrète d’une fonction récursive est
la suite de Fibonacci qui définien   par :

 U n  1, n  2 Cas de base


U n  U n2  U n1 , n  1 Appel récursif

ENSAH Introduction à l’algorithmique E.W. DADI – page : 17


…. la suite
Les étapes à suivre pour programmer une fonction récursive
sont :
On décompose le problème en un ou plusieurs sous-
problèmes du même type. On résout les sous-problèmes par
des appels récursifs.
Les sous-problèmes doivent être de taille plus petite que le
problème initial.
Enfin, la décomposition doit en fin de compte conduire à
un cas élémentaire, qui, lui, n’est pas décomposé en sous-
problème. (condition d’arrêt).

ENSAH Introduction à l’algorithmique E.W. DADI – page : 18


…. la suite
Exemple 2 : Problème de calcule de factorielle n!
Fact(n)= n!

( n - 1 )! * n =Fact(n-1) * n

( n - 2 )! * ( n-1 ) * n =Fact(n-2) * ( n-1 ) * n

( n - 3 )! * ( n-2 ) * ( n-1 ) * n =Fact(n-3) * ( n-2 )* ( n-1 ) * n

.
.
.

0! * ….* ( n-2 )* ( n-1 ) * n =Fact(0)*….* ( n-2 )* ( n-1 ) * n

ENSAH Introduction à l’algorithmique E.W. DADI – page : 19


3. Des exemples: algorithmes itératifs et récursifs
Pour montrer la différence et comment se fait le passage entre
un algorithme itératif vers un algorithme récursif, on va
utiliser quatre exemples, pour chacun on va donner la version
itérative et récursive.
Exemple 1: un algorithme qui calcule la somme des entiers
entre 1 jusqu'à N.
Exemple 2: un algorithme qui calcule le factorielle (N!).
Exemple 3: un algorithme qui calcule x à la puissance N.
Exemple 4: un algorithme qui permet trouver le plus grand
élément d’un tableau de N entiers.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 20


…. la suite
Exemple 1: Algorithme itératif
Fonction somme(N : Entier) : Entier;
Var i, S : Entier;
Début
S := 0; // Initialisation
Pour i allant de 1 jusqu'a N Faire // Progression
S := S + i; // Approximation
Fin
Retourner S;
Fin

ENSAH Introduction à l’algorithmique E.W. DADI – page : 21


…. la suite
Exemple 1: Algorithme récursif
Fonction somme(N : Entier) : Entier;
Début
Si (N=0) Alors
Retourner N;
Sinon
Retourner somme(N-1)+N;
FinSi
Fin
Idée de la récursivité :
SN = 1 + 2 + … + N
SN = (1 + 2 + … + N - 1) + N
SN = SN-1 + N // appel récursif
S0 = 0 // cas de base

ENSAH Introduction à l’algorithmique E.W. DADI – page : 22


…. la suite
Exemple 2: Algorithme itératif
Fonction factorielle(N : Entier) : Entier;
Var i, f : Entier;
Début
f := 1; // Initialisation
Pour i allant de 1 jusqu'a N Faire // Progression
f := f * i; // Approximation
Fin
Retourner f;
Fin

ENSAH Introduction à l’algorithmique E.W. DADI – page : 23


…. la suite
Exemple 2: Algorithme récursif
Fonction factorielle(N : Entier) : Entier;
Début
Si (N=0) Alors
Retourner 1;
Sinon
Retourner factorielle (N-1) * N;
FinSi
Fin

ENSAH Introduction à l’algorithmique E.W. DADI – page : 24


…. la suite
Exemple 3: Algorithme itératif
Fonction puissance(x: Réel, N : Entier) : Réel;
Var i, p : Entier;
Début
p := 1; // Initialisation
Pour i allant de 1 jusqu'a N Faire // Progression
p := p * x; // Approximation
Fin
Retourner p;
Fin

ENSAH Introduction à l’algorithmique E.W. DADI – page : 25


…. la suite
Exemple 3: Algorithme récursif
Fonction puissance(x: Réel, N : Entier) : Réel;
Début
Si (N=0) Alors
Retourner 1;
Sinon
Retourner puissance (x, N-1) * x;
FinSi
Fin

ENSAH Introduction à l’algorithmique E.W. DADI – page : 26


…. la suite
Exemple 4: Algorithme itératif
Fonction MaxTableau(A: Tableau, N : Entier) : Entier;
Var i, max : Entier;
Début
max := A[1]; // Initialisation
Pour i allant de 2 jusqu'a N Faire // Progression
Si (A[i] > max) Alors
max:=A[i];
FinSi
Fin
Retourner max;
Fin

ENSAH Introduction à l’algorithmique E.W. DADI – page : 27


…. la suite
Exemple 4: Algorithme récursif
Fonction MaxTableau(A: Tableau, N : Entier) : Entier;
Début
Si (N=1) Alors
Retourner A[1];
Sinon
Retourner max(MaxTableau(A, N-1) , A[N]);
FinSi
Fin
Idée de la récursivité :
Cas de base : si le tableau a un seul élément (N = 1), son plus
grand élément est A[1].
Appel récursif : si n > 1, le plus grand élément de A[1…N]
est le plus grand entre A[N] et le plus grand élément de
A[1…N-1].

ENSAH Introduction à l’algorithmique E.W. DADI – page : 28


IV. Preuve d’un algorithme
1. Présentation
Prouver un algorithme c’est de:
Vérifier qu’il se termine (preuve de terminaison) :
l’algorithme effectue un traitement qui nécessite un nombre
fini d’opérations élémentaires c’est-à-dire qu’il aboutit au
résultat au bout d’un nombre fini d’étapes.
Vérifier qu’il est correct (preuve de correction) :
l’algorithme fait bien ce qu’il est supposé faire dans sa
spécification c’est-à-dire qu’il produit toujours le bon
résultat pour toutes les instances du problème.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 29


2. Preuve de terminaison
La première qualité attendue d'un algorithme est bien sur sa
terminaison c’est-à-dire qu'il n'admette aucune instance pour
laquelle l’exécution rentre dans une boucle infinie.
Ce n’est pas toujours évident de prouver qu'un algorithme se
termine. Par exemple, la communauté scientifique n'a pas réussi à
prouver la terminaison de l'algorithme suivant:
Fonction syracuse(n : Entier) : mot;
Début
Tantque ( N  1) Faire
Si (N est pair ) Alors
N:=N/2;
Sinon
N:=3*N+1;
FinSi
FinTq
Retourner fini;
Fin

ENSAH Introduction à l’algorithmique E.W. DADI – page : 30


…. la suite
Comment prouver qu’un algorithme se termine?
Il n’y a pas de méthodes exactes pour prouver la terminaison
car dans la plupart des cas ça dépend de la nature de
l’algorithme.
Pour le cas des algorithmes itératifs, on analyse
généralement la condition d’arrêt de la boucle.
Pour le cas des algorithmes récursifs on procède par
récurrence. Pour prouver la terminaison d’une fonction
récursive, il faut montrer que la fonction parvient toujours
au traitement de cas de base en un nombre fini d’appels
récursifs.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 31


3. Preuve de correction
Pour le cas des algorithmes itératifs, la méthode générale
consiste à utiliser une propriété, dite « invariant de boucle »
liant les éléments variables d’une boucle et qui reste vraie
quelque soit le nombre de passage dans celle-ci. Cette
propriété se démontre par récurrence.
Pour le cas des algorithmes récursifs, on doit déterminer la
fonction calculée par l’algorithme. Pour prouver que
l’algorithme est correct on applique aussi la démonstration par
récurrence.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 32


4. Exemples
Exemple 1: Preuve de l’algorithme itératif suivant :
Fonction somme(N : Entier) : Entier;
Var i, S : Entier;
Début
1. S := 0;
2. Pour i allant de 1 jusqu'à N Faire
3. S := S + i;
4. Fin
5. Retourner S;
Fin
Preuve de terminaison : L’instruction (1) se termine. La boucle
(Pour) sera exécutée N fois. Le corps de la boucle est formé de
l’instruction (3) qui se compose d’une somme et d’une affectation,
donc elle se termine. Par conséquent, l’algorithme se termine.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 33


…. la suite
Preuve de correction :
a. Trouver un invariant de boucle : On notera par « xi » la valeur de la
variable « x » à la fin de l’itération « i ».
Les faits :
- S0 = 0; i0 = 1; Sj = Sj-1 + ij-1; pour j > 0
- ij = ij-1 + 1; pour j > 0 alors ij = j + 1; pour j >= 0.
D’après ce qui précède on déduit l’invariant de boucle :
Sj = 1 + 2 + … + j; pour j > 0.
b. Démonstration par récurrence :
N

Pour notre exemple, nous allons considérer la propriété : « P(N) : S N   i »


i 1

On va vérifier que la propriété est vraie tout N≥0 :


Cas de bas P(0): S0 = 0 (correspond à la phase d’initialisation). Donc
P(0) est vraie.
Cas récursifs : soit N ≥ 1 et supposons que la propriété P(N) est vraie.
Montrons qu’elle N
est vraie
N 1
pour N+1. Après l’itération (N+1), on a
S N 1  S N  N  1   i  ( N  1)   i , ce qui vérifier que l’algorithme est correct
i 1 i 1

ENSAH Introduction à l’algorithmique E.W. DADI – page : 34


…. la suite
Exemple 2: Preuve de l’algorithme itératif suivant :
Fonction f(n : Entier) : Entier;
Var x, y : Entier;
Début
1. x := n;
2. y := n;
3. Tant Que (y  0) Faire
4. x := x + 2;
5. y := y - 1;
6. FinTQ
7. Retourner x;
Fin

ENSAH Introduction à l’algorithmique E.W. DADI – page : 35


…. la suite
Preuve de terminaison : La condition de continuation de la boucle «
Tant Que » est y ≠ 0. La valeur initiale de y est n ≥ 0. Après chaque
itération, la valeur de y décroît d’une unité jusqu’à devenir 0. À ce
moment, la boucle « Tant Que » se termine après avoir été exécutée
n fois. Par suite, l’algorithme se termine.
Preuve de correction :
a. Trouver un invariant de boucle :
Les faits : D’après les faits:
 xj = xj-1 + 2
 x0 = n;
= xj-2 + 2 + 2
 y0 = n; = x0 + 2j = n + 2j
 xj = xj-1 + 2; pour j > 0  yj = yj-1 – 1
 yj = yj-1 - 1; pour j > 0 = yj-2 – 1 – 1
= y0 – j = n – j
Déduire l’invariant de boucle :
 xj + 2yj = n + 2j + 2n – 2j = 3n
 Alors l’invariant de boucle est xj + 2yj = 3n

ENSAH Introduction à l’algorithmique E.W. DADI – page : 36


…. la suite
b. Démonstration par récurrence : les contenues des variables x et y
après l’itération j de la boucle. Définissons la propriété suivante : «
P (j) : xj + 2yj = 3n » où n est l’argument de l’algorithme. Montrons
qu’il s’agit bien d’un invariant de boucle.
Cas de bas : on a x0 + 2y0 = n+2n=3n Donc la propriété P(0) est
vraie.
Cas récursifs : soit i ≥ 1 et supposons que la propriété P(i) est
vraie, c’est-à-dire que xj + 2yj = 3n . Montrons que P(i +1) est
vraie. À la fin de l’itération (i +1), on a : xj+1 + 2yj+1 = xj + 2 +
2yj – 2 = xj + 2yj = 3n
Ce qui prouve P(i +1) est vérifiée. L’invariant de boucle est alors
prouvé.
Après la terminaison de l’exécution de la boucle, on a : yn = 0, xn =
3n - 2yn = 3n, Donc, l’algorithme retourne 3n.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 37


…. la suite
Exemple 3: Preuve de l’algorithme récursif suivant :
Fonction F(n: entier) :Entier
Début
1. Si (n = 0) Alors Retourner 2 ;
2. Sinon Retourner F(n −1) * F(n −1) ;
3. FinSi
Fin
Preuve de terminaison :
Cas de base : l’appel de la fonction F avec le paramètre n = 0 retourne
directement 2 sans faire aucun appel récursif. Dans ce cas l’algorithme se
termine immédiatement.
Cas récursifs : soit n ≥ 1 un entier et supposons que l’appel de la fonction F
avec le paramètre n se termine c’est-à-dire F(n)=F(n-1)*F(n-1). L’appel de la
fonction F avec le paramètre (n+1) entraîne deux appels récursifs à F avec le
même argument n (F(n+1)=F(n)*F(n)). Ces deux derniers appels se terminent
par hypothèse. Le résultat sera obtenu après multiplication de ces deux appels
et puisqu’il s’agit d’une opération élémentaire qui se termine, alors, l’appel de
F avec l’argument (n+1) se termine aussi. Par conséquent, l’algorithme se
termine.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 38


…. la suite
Preuve de correction :
Pour ce faire, il faut savoir tout d’abord que calcule cet
algorithme pour un entier n donné en entrée.
Deux méthodes sont possibles pour cet algorithme:
Par le calcul des premières valeurs pour F :
 F(0) = 2
 F(1) = F(0) * F(0) = 22
 F(2) = F(1) * F(1) = 22 * 22 = 24
 F(3) = F(2) * F(2) = 24 * 24 = 28
On peut faire la conjecture suivante : F (n)  2
2n

Par décomposition :
 F(n) = F(n −1)2
= (F(n −2)2)2
= ((F(n −3)2)2)2
 F (0)  2
2n 2n

ENSAH Introduction à l’algorithmique E.W. DADI – page : 39


…. la suite
Il reste à prouver que l’algorithme calcule bien F n  22 pour
n

tout n et ceci en utilisant la démonstration par récurrence.


D’après l’algorithme on a :
 F (0)  2

 F n   F n  1  F n  1  F n  12
, n  1
Montrons par récurrence pour tout entier naturel n on a : F n  2 2n

Cas de base : la propriété est vraie pour n = 0, car F 0  22  2


0

Cas récursifs : soit n ≥ 1 et supposons que la propriété F n   2 2n

est vraie. Montrons qu’elle vraie pour n+1:


On a : F n  1  F n F n  F n
2

Alors : F n  1  (2 )  2  2
2n 2 2 n 2 2n1

D’où, la propriété est vraie pour n+1.


Conclusion : l’algorithme est correct.

ENSAH Introduction à l’algorithmique E.W. DADI – page : 40


Chapitre 2: Complexité algorithmique
Plan
I. Notion de la complexité algorithmique
II. Outils mathématiques pour la complexité
III.Calcul de la complexité d’un algorithme

ENSAH Complexité algorithmique E.W. DADI – page : 42


I. Notion de la complexité algorithmique
1. Activité
Problème: Rechercher dans un tableau l’existence d’un
élément.
Il est très fréquent qu’il soit nécessaire de chercher un élément
dans un tableau (exemple recherche d’un mot dans
dictionnaire) .
Etant donné un tableau trié T de n entiers, on veut vérifier si
un entier x se trouve dans ce tableau. Plusieurs solutions pour
ce problème sont possibles.
Solution 1 (recherche séquentielle version 1) : Une solution
très simple consiste à parcourir le tableau A de 1 jusqu’à n et à
chaque parcours i on test si x=T[i].

ENSAH Complexité algorithmique E.W. DADI – page : 43


…. la suite
Algorithme Recherche Séquentielle Version 1
Fonction Rech_séq_v1 (T : Tableau, n, x : Entier) : Entier
Var i : Entier;
Début
test:=0;
Pour i := 1 à n Faire
Si(T[i] = x) Alors test :=1 FinSi
FinPour
Retourner(test );
Fin
L'algorithme ci-dessus fonctionne mais à le défaut de continuer à
parcourir le tableau même quand l'élément a été trouvé. C’est-à-dire
qu’il va parcourir tout le tableau même si l’élément qu’on cherche
peut être existe au début du tableau ou avant d'être sûr qu’il ne se
trouve pas dans le tableau.

ENSAH Complexité algorithmique E.W. DADI – page : 44


…. la suite
Solution 2 ( Recherche séquentielle version 2) : Une amélioration
de l’algorithme précédent consiste à arrêter d’avancer lorsqu'un
premier élément de tableau satisfaisant la condition T[i]=x est
trouvé.
Algorithme Recherche Séquentielle Version 2
Fonction Rech_séq_v2 (T : Tableau, n, x : Entier) : Entier
Var i : Entier;
Début
i := 1;
trouve:=faux; i:=1;
Tant que( i<=n et trouve = faux) Faire Tant que(T[i]≠ x et i<=n) Faire
Si(T[i] = x) Alors i++;
trouve:=vraie; FinTQ
Retourner(i);
Si(i>n) alors Retourner(-1);
FinSi
i++;
Sinon Retourner(i);
FinTQ FinSi
Retourner(-1);
Fin

ENSAH Complexité algorithmique E.W. DADI – page : 45


…. la suite
L’inconvénient de l’utilisation de l’algorithme recherche
séquentielle pour la recherche d’une valeur dans un tableau
trié est lorsque la valeur qu’on cherche se trouve à la fin de ce
tableau; dans ce cas il faut traverser tout le tableau avant de
trouver la valeur ou avant d'être sûr qu’elle ne se trouve pas
dedans.
Par exemple : lors de la recherche dans un tableau de 1000
éléments: la recherche séquentielle peut entraîner 1000
exécutions de la boucle si la valeur qu’on cherche se trouve à
la fin de tableau.

ENSAH Complexité algorithmique E.W. DADI – page : 46


…. la suite
Solution 3 (Recherche dichotomique) : Lors de la recherche
dichotomique, on élimine la moitié des éléments du tableau à
chaque exécution de la boucle. Ainsi, la recherche se termine
beaucoup plus rapide comparé à l’algorithme séquentielle. A noter
que cet algorithme ne fonctionne que pour les tableaux triés.
Algorithme Recherche Dichotomique Version récursive
Fonction R_dicho(T: Tableau, debut, fin : Entier) : Entier
Var m : Entier; // indice du milieu
Début
Si(debut > fin) Alors Retourner(0); FinSi
m := (debut+fin)/2;
Si(x= T[m]) Alors Retourner(m); FinSi
Si(x > T[m]) Alors Retourner(R_dicho(T, m+1, fin));
Sinon Retourner(R_dicho(T, debut, m-1));
FinSi
Fin

ENSAH Complexité algorithmique E.W. DADI – page : 47


3. Complexité d’un algorithme
Pour un problème donné il se peut qu’il existe plusieurs algorithmes
permettant de le résoudre, mais souvent le temps de calcul pris par chaque
algorithme n’est pas le même, certaines algorithmes sont moins rapides que
d’autres.
Par exemple si on compare le temps d’exécution des deux algorithmes
(séquentielle et dichotomique) sur un même tableau et sur une même
machine dans le cas où la valeur se trouve à la fin du tableau on trouverai
que l’algorithme de recherche dichotomique est plus rapide que la
recherche séquentielle.
Les questions qui se pose est est-ce qu’il existe des outils pour comparer
théoriquement le temps d’exécution pour dire qu’algorithme est efficace
par rapport à l’autre ?
On mesure l'efficacité d'un algorithme par l’analyse de sa complexité(
c’est-à-dire on passe par le contraire :efficace # complexe).
La complexité d'un algorithme c’est la quantité de ressources qu'il exige
(mémoire ou temps-processeur) pour son exécution.
Dans ce cours une intérêt particulier est donnée à l’étude de l’efficacité
d’un algorithme en terme de temps d’exécution (Complexité temporelle).

ENSAH Complexité algorithmique E.W. DADI – page : 48


…. la suite
L’analyse de la complexité algorithmique permet de prédire
l'évolution en temps calcul nécessaire pour amener un
algorithme à son terme, en fonction de la quantité de données
à traiter.
La complexité c’est une mesure qui permet de faire
différencier les algorithmes, elle permet également de
caractériser la classe de famille de l’algorithme.
Cette complexité est indépendante de la vitesse de la machine
sur laquelle est exécuté l’algorithme.
Elle donne une estimation du temps d’exécution de
l’algorithme sans tenir compte de son environnement (système
d’exploitation, compilateur, technologie, …).
Cette estimation se détermine en fonction du nombre
d’opérations de base effectuées par l’algorithme c’est-à-dire en
fonction de la taille des données en entrée de cet algorithme.

ENSAH Complexité algorithmique E.W. DADI – page : 49


…. la suite
Le temps d’exécution de l’algorithme est proportionnel au
nombre d’opérations qu’il effectue. Parmi ses opérations, on
en considère les plus importantes, celles qui sont
représentatives de l’effort de calcul.
Exemples :
Problème de recherche d’un élément : la comparaison à cet
élément.
Algorithme de tri : la comparaison entre les éléments du
tableau, mais aussi le déplacement des éléments.
Problème de calcul de la puissance : la multiplication.
La complexité exacte d’un algorithme est plus difficile à
déterminer. On ne s’intéresse qu’à la complexité dite
asymptotique.

ENSAH Complexité algorithmique E.W. DADI – page : 50


II. Outils mathématiques pour la complexité
1. Notations asymptotiques
Notation grand O (Grand-O) : Une fonction g(n) est une borne supérieure
asymptotique de f(n), si et seulement si:
( C  0), ( n0  0) : f(n)  Cg(n), ( n  n0).
On note alors : f(n) = O(g(n)).
Notation grand  (Grand-Omega) : Une fonction g(n) est une borne inférieure
asymptotique de f(n), si et seulement si :
( C  0), ( n0  0) : f(n)  Cg(n), ( n  n0).
On note alors : f(n) = (g(n)).
Notation grand  (Grand-Theta) : Deux fonctions f(n) et g(n) ont même ordre de
grandeur asymptotique, si et seulement si :
( C1  0), ( C2  0), ( n0  0) : C1g(n)  f(n)  C2g(n), ( n  n0).
On note alors : f(n) = (g(n)).
Remarques :
f(n) = (g(n))  f(n) = O(g(n)) et f(n) = (g(n)).
La notation « f(n) = O(g(n)) » (resp (g(n)), ou (g(n))) n’est pas une égalité
mathématique ce sont des conventions d’écriture.

ENSAH Complexité algorithmique E.W. DADI – page : 51


…. la suite

ENSAH Complexité algorithmique E.W. DADI – page : 52


…. la suite
Exemple 1: f(n)=a*n+b, g(n)=n, on a : f(n) = O(g(n)).
En effet : comme a*n+b  a*n+b*n  (a+b)n ,  n  1, alors : ( C = a+b  0), ( n0 = 1
 0) : f(n)  Cg(n), ( n  n0).
Exemple 2: Pour f(n) = n3 + 5n2 - 7n + 18 et g(n) = n3, on a : f(n) = O(g(n)).
En effet : comme 5n2  5n3, -7n  7n3 et 18  18n3,  n  1, alors :
f(n) = n3 + 5n2 - 7n +18  n3 + 5n3 + 7n3 +18n3.
f(n)  31n3 = 31g(n).
( C = 31  0), ( n0 = 1  0) : f(n)  Cg(n), ( n  n0).
Exemple 3: Pour f(n) = 5n2log(n) + 1 et g(n) = n, on a : f(n) = (g(n)).
En effet :
5n2  5n, ( n  0).
log(n)  1, ( n  e = 2.7182883).
f(n) = 5n2log(n) + 1  5n + 1  4n, ( n  3).
f(n)  4g(n), ( n  3).
( C = 4  0), ( n0 = 3  0) : f(n)  Cg(n), ( n  n0).
Exemple 4: Pour f(n) = 3n2 + 2n + 1 et g(n) = n2, on a : f(n) = (g(n)).
En effet :
3n2 + 2n + 1  3n2 + 2n2 + n2 = 6n2 ( n  1).
3n2 + 2n + 1  2n2 ( n  0).
( C1 = 2  0), ( C2 = 6  0), ( n0 = 1  0) : C1g(n)  f(n)  C2g(n), ( n  n0).

ENSAH Complexité algorithmique E.W. DADI – page : 53


2. Propriétés des notations asymptotiques
Réflexivité :
f(n) = O(f(n)).
f(n) = (f(n)).
f(n) = (f(n)).
Symétrie de  :
f(n) = (g(n))  g(n) = (f(n))
Symétrie transposée de O et  :
f(n) = O(g(n))  g(n) = (f(n))
Transitivité :
f(n) = O(g(n)) et g(n) = O(h(n))  f(n) = O(h(n)).
f(n) = (g(n)) et g(n) = (h(n))  f(n) = (h(n)).
f(n) = (g(n)) et g(n) = (h(n))  f(n) = (h(n)).

ENSAH Complexité algorithmique E.W. DADI – page : 54


3. Formules de sommations
Soit une suite numérique (an)n0. La somme finie de cette suite est
notée : i=1,…,n(ai) = a1 + … + an
Exemples :

n
n(n  1) n
(2n  1)(n  1)n
 i  i2  6
i 1 2 i 1

n
n 2 (n  1) 2 n
n
 i 
3

4
i4 
i 1 30
(n  1)(2n  1)(3n 2  3n  1)
i 1

n
x n 1  1

i 0
x  i

x  1
, si x  1

ENSAH Complexité algorithmique E.W. DADI – page : 55


4. Fonctions classiques
Fonction logarithmique :
(∀a > 0)(∀b > 0)(∀c > 0)(∀n∈ IN), la fonction logarithme f(n) = logb(n) =
log(n)/log(b); où b est la base du logarithme.
Quelques propriétés: logc(ab)=logc(a)+logc(b), logban =nlogba, logban =nlogba ,
log a log n log a
log b a  b
, a  n , a  blog a
b b

log b
Fonction polynomiale :
P(n) = adnd + … + a2n2 + a1n + a0, avec la condition ad  0.
Théorème : f(n) = adnd + … + a1n + a0 = (nd).
Fonction exponentielle :
f(n) = an; où a  1 (a c’est la base de l’exponentielle).
Remarques :
Une fonction polynomiale (asymp. positive) croît plus vite que
n’importe quelle fonction logarithmique.
Une fonction exponentielle quelconque avec une base > 1 croît plus
vite que n’importe quelle fonction polynomiale.

ENSAH Complexité algorithmique E.W. DADI – page : 56


5. Classes de complexité
Les algorithmes usuels peuvent être classés en un certain nombre de classes de
complexité.
Un algorithme est dit optimal si sa complexité est la complexité minimale
parmi les algorithmes de sa classe.
Les complexités les plus utilisées sont :
Constante O(1) : Accéder au premier élément d'un ensemble de données
Logarithmique O(log n) : Couper un ensemble de données en deux parties
égales, puis couper ces moitiés en deux parties égales, etc.
Linéaire O(n) : Parcourir un ensemble de données
Quasi-linéaire O(nlog n) : Couper répétitivement un ensemble de données
en deux et combiner les solutions partielles pour calculer la solution
générale
Quadratique O(n2) : Parcourir un ensemble de données en utilisant deux
boucles imbriquées
Polynomiale O(np) : Parcourir un ensemble de données en utilisant p
boucles imbriquées
Exponentielle O(an) : Générer tous les sous-ensembles possibles d'un
ensemble de données

ENSAH Complexité algorithmique E.W. DADI – page : 57


…. la suite
Comparaison des classes de complexité

On considère que Une année comporte


toute instruction à peu prés 3.109
possède une durée Secondes
de 10-6 secondes.

ENSAH Complexité algorithmique E.W. DADI – page : 58


II.Calcul de la complexité
1. Généralités
Le temps d’exécution d’un algorithme pour une entrée particulière
est le nombre d’opérations élémentaires, ou « étapes », exécutées.
Une opération élémentaire est une opération qui s’effectue en temps
constant (O(1)) sur tous les calculateurs usuels. Exemples :
Comparaisons;
Affectations;
Opérations arithmétiques et logiques;
Entrée-sortie;
lecture ou écriture d’une variable simple;
accès à un tableau.
La complexité d’un algorithme est la somme des complexités de
chacune de ces instructions.

ENSAH Complexité algorithmique E.W. DADI – page : 59


2. Quelques règles
Pour les instructions conditionnelles (Si…Alors… Sinon …), on
considère la complexité maximale entre chaque branche et la condition. La
complexité de l’instruction : Si (C) alors I1 sinon I2 est max(O(f(n)),
O(f1(n)), O(f2(n))), tels que O(f(n)), O(f1(n)), O(f2(n)) sont respectivement
les complexités de la condition,des instructions I1 et I2.
Boucle simple : O(n) si le corps de la boucle est O(1)
Double boucle : O(n2) si le corps de la boucle est O(1)
Généralement pour une boucle de type suivant :
Pour i:=0 à n Faire
I1
FinPour
Sa complexité est donnée en (n*f1(n)), f1(n) c’est la complexité de I1.
Dans le cas de la boucle « Tant que » et au cas où la complexité de la
condition testée par cette boucle est (f(n)). Dans ce cas la complexité est
en (g(n)*max(f(n),f1(n))). (g(n)) complexité en nombre d’itérations,
(f1(n)) complexité de l’instruction exécutée par la boucle.

ENSAH Complexité algorithmique E.W. DADI – page : 60


…. la suite
Exemples
Algorithme 1 Algorithme 2
Début Début
Réaliser l'opération a + b Pour i =1 à n faire
Fin Afficher i
Complexité = O(1) (constant) FinPour
Fin
Complexité = O(n) (linéaire)
Algorithme 3 Algorithme 4
Début Début
Pour i = 1 à n faire Pour i =1 à n faire
Pour j = i à n faire Pour j = i à n faire
Afficher i*j Pour k = i à n faire
FinPour Afficher i*(j+k)
FinPour FinPour
Fin FinPour
Complexité = O(n2) (quadratique) FinPour
Fin
Complexité = O(n3) (cubique)

ENSAH Complexité algorithmique E.W. DADI – page : 61


3. Complexité des algorithmes itératifs
Les étapes à suivre pour calculer le temps d’execution d’un algorithme
itératif sont :
On considère que chaque ligne de l’algorithme s’exécute en un temps
constant indépendant de la taille de données. On note ci le temps
d’exécution de l’instruction numéro i.
Chaque instruction de l’algorithme est suivi de son coût ci ainsi que du
nombre de fois où elle est exécutée.
Le temps total d’exécution d’un algorithme traitant une donnée de taille n,
noté T(n) est égal à la somme des coûts pondérés par le nombre
d’exécution de chaque instruction.
Exemple 1:
Pour i: =1 à n faire - Les instructions de cet exemple sont, i<=n, i=i+1; I1
I1 - On considère c1, c2 et c3 respectivement les couts des trois instructions.
- La boucle “Pour” s’exécute n fois et donc les 3 instructions s’exécutent
Fin aussi n fois.
- T(n)= (c1+c2 + c3 )n

ENSAH Complexité algorithmique E.W. DADI – page : 62


…. la suite
Exemple 2 : complexité d’un algorithme itératif
Prenant de calculer la complexité de l’algorithme de recherche d’un
élément dans un tableau (Rech_séq_v1)
Algorithme Rech_séq_v1 Coût Fois
Var i : Entier;
Début
Pour i := 1 à n Faire c1 , c2 n+1, n
Si(T[i] = x) Alors c3 n
Retourner(i); c4 n
FinSi
FinPour
Retourner(-1); c5
Fin

T(n) = c1(n+1)+(c2+c3+c4)n +c5


T(n) = a*n+b
D’où T(n)= O(n)

ENSAH Complexité algorithmique E.W. DADI – page : 63


4. Complexité des algorithmes récursifs
Les étapes à suivre pour le calcul de temps d’exécution d’un
algorithme récursif sont :
Transformation de l’algorithme sous forme d’une équation de
récurrence.
Résolution de l’équation en utilisant les techniques de
résolutions de récurrence.
Il existe deux types d’équations de récurrences :
a)Equation de récurrence de partitions : c’est une équation de la
forme suivante :
 d ; si n  n0

T ( n)   n
 b )  f (n)
aT (

a c’est le nombre d’appels récursifs, f(n) c’est la complexité de


regroupement entre les différents appels. Elle est utilisée pour les
algorithmes où il y a la division de l’entrée à chaque appel récursif.

ENSAH Complexité algorithmique E.W. DADI – page : 64


…. la suite
Méthodes de résolution de la récurrence de partitions :
Méthode par itérations : on explore T(n) suivant des itérations
jusqu’au cas de base.
Théorème de Master.
Méthode par itérations : pour montrer comment résoudre une
équation de récurrence de partition on va utiliser l’exemple suivant :
T(n) = 2T(n/2)+n
= 2[2T(n/4) + n/2]+n
= 2[2(2T(n/8) + n/4) + n/2]+n
= 23T(n/8)+ 3n
= 2iT(n/ 2i)+ i * n
Quand (n/ 2i)= 1  log2i = log n  i =(log n / log2)  i= log2n
T (n)  2log2 n  n log 2 n
T (n)  n  n log 2 n
D’où T (n)  (n log 2 n)

ENSAH Complexité algorithmique E.W. DADI – page : 65


…. la suite
Théorème de Master : Selon ce théorème on a :
Si f (n)  cn k , k  0, c  0
 (n k ); a  b k

T (n)  (n k log b n); si a  b k
 (n logb a ); si a  b k

Si f (n)  cn k (log b n)q , k  0, c  0


 (n k ); si a  b k et q  0
 q 1
 (n (log b n) ); si a  b et q  1
k k
T ( n)  
  ( n k
log b log b n ); si a  b k
et q  1
(n logb a ); si (a  b k et q  1)ou a  b k

ENSAH Complexité algorithmique E.W. DADI – page : 66


…. la suite
Théorème de Master : Exemples
Exemple 1 : T(n) = 2T(n/2) + n
a = 2; b = 2; k = 1.
a= bk
T(n) = (n log2(n)).
Exemple 2 : T(n) = 9T(n/3) + n2
a = 9; b = 3; k = 2.
T(n) = (n2log3(n)).
Exemple 3: T(n) = 2T(n/2) + n3
a = 2; b = 2; k = 3.
T(n) = (n3).

ENSAH Complexité algorithmique E.W. DADI – page : 67


…. la suite
Exemple : complexité d’un algorithme récursif
Prenant de calculer la complexité de l’algorithme recherche
dichotomique (la version R_dicho)
Fonction R_dicho(T: Tableau, debut, fin : Entier) : Entier
Var m : Entier; // indice du milieu Coût
Début
Si(debut > fin) Alors Retourner(0); FinSi c1
m := (debut+fin)/2; c2
Si(x = T[m]) Alors Retourner(m); FinSi c3
Si(x > T[m]) Alors Retourner(R_dicho(T, m+1, fin)); T(n/2)
Sinon Retourner(R_dicho(T, debut, m-1)); T(n/2)
FinSi
Fin
Soit n= debut+fin-1 la taille du tableau
L’équation de récurrence correspondante à cet algorithme est
T(n) = c1+c2+ c3+ T(n/2)
= T(n/2) +cte.
On a k=0, a=1 et b=2 => a=bk
D’après le théorème de master T(n)=O(n0log2n)= O(log2n)

ENSAH Complexité algorithmique E.W. DADI – page : 68


…. la suite
b) Récurrence linéaire
La forme générale d’une équation de récurrence linéaire est
comme suite:
T(n)-a1T(n-1)- a2T(n-2)-…- akT(n-k)=cte.
A une telle équation, on peut l’associer un polynôme:
P(x)=xk - a1xk-1 - a2xk-2 -…- ak
La résolution de ce polynôme nous donne m racines ri (avec
m<=k).
La solution de l’équation de récurrence est ainsi donnée par :
T(n)=c1r1n +c2r2n +c3r3n +…+cmrmn

ENSAH Complexité algorithmique E.W. DADI – page : 69


…. la suite
Exemple : utilisation de la récurrence linéaire pour calculer la
complexité de la suite récursive de Fibonacci {F(n)=F(n-
1)+F(n-2), F(0)= F(1)=1}
L’équation de récurrence correspondante à F est T(n)=T(n-
1)+T(n-2)+cte.
Le polynôme correspondant à l’équation de recurrence T
est : P(x)= x2 – x – 1, la résolution de cette équation donne:
1 5 1 5
r1  , r2 
2 2
n n
1 5  1 5 
T (n)  a  r1  b  r2  a
n n
  b
 


 2   2 
  1  5 n 
T (n)     

 2  
 

ENSAH Complexité algorithmique E.W. DADI – page : 70


4. Niveaux de complexité
Soit D l'ensemble des données de taille n et T(d) le coût de
l'algorithme sur la donnée de taille d.
Complexité au meilleur : C’est le plus petit nombre d’opérations
qu’aura à exécuter l’algorithme sur un jeu de données de taille fixée, ici
à n. C’est une borne inférieure de la complexité de l’algorithme sur un
jeu de données de taille n.
Tmin(n)=min dєDT(d)
Complexité au pire : C’est le plus grand nombre d’opérations qu’aura
à exécuter l’algorithme sur un jeu de données de taille fixée, ici à n.
Tmax(n)=max dєDT(d)
Complexité en moyenne : C’est la moyenne des complexités de
l’algorithme sur des jeux de données de taille n en tenant compte de la
probabilité d’apparition de chacun des jeux de données(p(d)).
Tmoy(n)=∑ dєDp(d)T(d)

ENSAH Complexité algorithmique E.W. DADI – page : 71


…. la suite
Exemple :
Prenant de calculer la complexité de l’algorithme de recherche
séquentielle dans un tableau (la version 2 Rech_séq_v2).
Le calcul de la complexité de Rech_séq_v2 se fait selon trois
niveau :
Complexité au meilleur: le meilleur des cas est lorsque la valeur
qu’on cherche se trouve au début de tableau, dans ce cas l’algorithme
va faire qu’une seule itération d’où la complexité = O(1) .
Complexité au pire: le pire des cas est lorsque la valeur qu’on cherche
n’existe pas dans le tableau ou bien elle se trouve à la fin. Dans les
deux cas on doit parcourir le tableau de début jusqu’à la fin d’où la
complexité = O(n) .
Complexité en moyenne: la moyenne des cases est lorsque la valeur
qu’on cherche se trouve au milieu ou à une position i proche du milieu.
Le nombre de comparaison dans ce cas est i tels que 1<i<n, le jeu de
données est d=[2,i], T(d)=O(i). Par ailleurs, si l’on suppose que toutes
les positions de x dans le tableau sont équiprobables, la probabilité p(d)
qu’une donnée x appartienne à d est égale à 1/n. La complexité
moyenne se calcule alors de la façon suivante :
n n
i n 1
T ( n)   p ( d )  T ( d )   
i 1 i 1 n 2

ENSAH Complexité algorithmique E.W. DADI – page : 72


Chapitre 3: Étude de la complexité de
quelques algorithmes
Plan
I. Algorithmes itératifs
II. Algorithmes « diviser pour régner »
III.D’autres algorithmes

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 74


I. Algorithmes de tri itératifs
1. Généralités
Problème de tri : étant donné un tableau T non trié, le problème de
tri consiste à utiliser un algorithme de tri pour ranger les valeurs de
tableau T dans un ordre (un sens) donné(croissant/décroissant).
Exemple A={3, 7, 9, 2, 4, 6, 8} le trie de ce tableau dans l’ordre
croissant donne A={1, 2, 3, 4, 6, 7, 8, 9}
Plusieurs situations nécessite le tri à savoir :
établir le classement de certains élèves,
mettre en ordre un dictionnaire,
faire une sortie lisible d'un correcteur d'orthographe,
etc …
Il existe plusieurs algorithme de tri dans la littérature, à savoir : tri
par sélection, tri par insertion, tri rapide, tri fusion…
Dans la suite on va traiter le cas de trie d’un tableau dans l’ordre
croissant.

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 75


2. Tri par sélection
L’idée de cette algorithme est basée sur un autre algorithme;
celui qui permet de trouver la valeur minimale ou maximale
d’un tableau. On peut choisir d’utiliser l’un des deux
algorithme (min ou max), si l’algorithme choisit est min, le tri
commence par le début de tableau le contraire est vrai.
À chaque itération de l’algorithme tri par sélection, les étapes
à suivre sont :
Chercher le minimum (resp. maximum) du la partie de
tableau non encore trié.
Échanger le minimum (resp. maximum) avec le premier
(resp. dernier) élément de la partie du tableau non encore
trié.

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 76


…. la suite
Algorithme de tri par sélection (le cas d’utiliser l’algorithme
min_tableau)
Fonction Tri_sélection(T : Liste, n : Entier)
Var i, imin : Entier;
Début
Pour i : = 1 à n-1 Faire
imin := Obtenir_min(T, i, n);
Si(imin i) Alors Échanger(T, i, imin) FinSi
FinPour
Fin

Source :wikipedia.org

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 77


…. la suite
Fonction Obtenir_min(A : Liste, d, f : Entier) : Entier
Var i, j : Entier;
Début
j := d;
Pour i : = d + 1 à f Faire
Si(A[i] < A[j]) Alors j := i; FinSi
FinPour
Retourner(j);
Fin
Fonction Echanger(A : Liste, i, j : Entier)
Var t : Entier;
Début
t := A[i];
A[i] := A[j];
A[j] := t;
Fin

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 78


…. la suite
Exemple:

51 2 3 4 5
5 9 7 3 8

i=1 3 9 7 5 8 imin= 4, changement

i=2 3 5 7 9 8 imin= 4, changement

i=3 3 5 7 9 8 imin= 3, pas de changement

i=4 3 5 7 8 9 imin= 4, changement

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 79


…. la suite
Etude de la complexité de l’algorithme Tri_sélection :
La complexité de l’algorithme tri_selection = (n-1)*(complexité
de Obtenir_min + complexité de Echanger)
La complexité de l’algorithme Obtenir_min est linéaire; il dépend
directement de la taille de l’entrée. Si on considère la taille de
l’entrée est k alors C(k)=k
La complexité de l’algorithme Echange est constante.
D’où C(n) = (n+c)+((n-1)+c)+ …+(2+c)
= n+(n-1)+…+2+n*c
= n*c+ n*(n-1)/2
= n(c+(n-1)/2)
= n((n-1+2c)/2) ≤ (1+c) n2
Ce qui implique que C(n)= O(n²).

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 80


3. Tri par insertion
Idée : À chaque itération de l’algorithme : on place le
premier élément dans le tableau non encore trié dans sa
place convenable dans la partie déjà trié du tableau,
comme un joueur tiens des cartes à jouer.
51 2 3 4 5
i=2 5 9 7 3 8 5 9 7 3 8

i=3 5 9 7 3 8 5 7 9 3 8

i=4 5 7 9 3 8 3 5 7 9 8

i=5 3 5 7 9 8 3 5 7 8 9

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 81


…. la suite
Fonction Tri_insertion(T : Tableau, n : Entier)
Var i, j, clé : Entier;
Début
Pour i : = 2 à n Faire
clé:= T[i]; // sauver a[i]
j := i - 1;
Tant Que((j > 0) et (T[j] > clé)) Faire
T[j + 1] := T[j]; // Décalage
j--;
FinTQ
T[j+1] = clé;
FinPour
Fin

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 82


…. la suite
Soit C(n) le nombre de comparaisons effectuées par le tri par
sélection.
Dans le pire des cas :
Configuration : un tableau trié dans l’ordre décroissant.
Placer T[i] dans T[1…i-1] nécessite (i-1) comparaisons.
C(n) = 1 + … + (n-1) = i=2,..,n(i-1) = (n-1)n/2
C(n) = O(n2).
Dans le meilleur des cas :
Configuration : un tableau trié dans l’ordre croissant.
Placer T[i] dans T[1…i-1] nécessite 1 comparaison.
C(n) = i=2,..,n(1) = (n-1)
C(n) = (n).

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 83


4. Tri à bulles
Idée :
Consiste à permuter les éléments adjacents s’ils ne sont pas ordonnés.
Continuer ce processus jusqu’à ce que le tableau soit entièrement trié.
À chaque itération i, on parcourt le tableau de droite à gauche pour
placer le minimum dans la position i par une suite d’échange
d’éléments adjacents.
51 2 3 4 5
5 9 7 3 8

i=1 3 5 9 7 8

i=2 3 5 7 9 8

i=3 3 5 7 8 9

i=4 3 5 7 8 9

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 84


…. la suite
Algorithme :
Fonction Tri_bulles(T : Tableau, n : Entier)
Var i, j : Entier;
Début
Pour i : = 1 à (n - 1) Faire
Pour j := n à (i + 1) Faire
Si(T[j] < T[j - 1]) Alors Échanger(T, j - 1, j); FinSi
FinPour
FinPour
Fin
Complexité :
Soit C(n) le nombre de comparaisons effectuées par le tri à bulles.
À chaque itération i (de 1 à n-1), on effectue (n - i) comparaisons.
C(n) = (n-1) + … + 1 = i=1,..,n-1(n-i)= (n-1)n/2
C(n) = (n2).

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 85


5. Tri PRAM
C’est un algorithme de tri très adapté à la parallélisation. Il permet
de faire le tri de façon très rapide sur des machines multi-cœurs,
Stations multiprocesseurs, Grille de calculs…
Idée :
Le tableau à trier est placé sur la première ligne d'une grille. Son
transposé (Le même tableau) est aussi placé en colonne. Puis, de
1 jusqu’à n, on compare chaque élément avec les n autres de
tableau (les comparaisons entre chaque couple formé par une
valeur ligne et une valeur colonne). Si la comparaison est vraie
on met à l'emplacement correspondant de la grille, la valeur 1,
sinon 0.
Après avoir terminé, on somme les éléments des lignes de la
grille (matrice de 0 et 1) dans un nouveau vecteur. Ces sommes
donnent la position (l’ordre de tri) de chacune des valeurs du
tableau à trier.

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 86


…. la suite
Exemple :

≥ 5 9 7 3 8 P
5 1 0 0 1 0 2 On obtient
9 1 1 1 1 1 5 l’ordre de tri

7 1 0 1 1 0 3
3 0 0 0 1 0 1
8 1 0 1 1 1 4

T[ ]= 5 9 7 3 8

P[ ]= 2 5 3 1 4 Tableau trié

i=1, TT[2]=T[1]
i=2, TT[5]=T[2]
TT[P[i]]= T[i] => i=3, TT[3]=T[3] => 3 5 7 8 9
i=4, TT[1]=T[4]
i=5, TT[4]=T[5]

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 87


…. la suite
Algorithme :
Fonction Tri_PRAM(T : Tableau, n : Entier)
Var i, j : Entier;
Début
Pour i : = 1 à n Faire
S:=0;
Pour j := 1 à n Faire
Si(T[i] ≥ T[j]) Alors S+:=1; FinSi
FinPour
P[i]=S;
FinPour
Pour i : = 1 à n Faire
TTrie[P[i]]:=T[i]
FinPour
//T:=TTrie;
Fin
Il est bien clair que la complexité de Tri_PRAM est en O(n²).

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 88


II. Algorithmes «diviser pour régner»
1. Présentation
Ce sont les algorithmes récursifs qui utilisent une stratégie de type Diviser
pour régner « D&R ».
Elle suit une approche de décomposition descendante d’un problème en
sous-problèmes de tailles plus petites.
Elle repose sur trois étapes fondamentales :
Diviser : on partitionne le problème initial en un certain nombre de
sous-problèmes identiques, mais de tailles plus petites.
Régner : on résout les sous-problèmes d’une manière récursive.
Cependant, un sous-problème peut être résolu directement si sa taille
est suffisamment réduite.
Combiner : on combine les solutions partielles des sous-problèmes
pour construire la solution globale du problème initial.
La complexité d’un algorithme de type D&R est donnée par la résolution
de l’équation de récurrence de partitions T(n) = aT(n/b) + О(f(n))
correspondante.
Exemples: Recherche dichotomique, Tri par fusion, Algorithme de
Karatsuba, Algorithme de Strassen…

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 89


2. Algorithme de tri par fusion
Idée :
Diviser le tableau de taille n, en 2 sous-tableaux de taille n/2 chacun.
Trier chacun des 2 sous-tableaux séparément (par appel récursif).
Interclasser les deux sous-tableaux déjà triés pour obtenir un seul
tableau trié. 51 2 3 4 5
Algorithme : 5 9 7 3 8
Fonction Tri_fusion(T : Tableau, d, f : Entier)
5 9 7 3 8
Var m : Entier;
Début 5 9 7 3 8
Si(d < f) Alors
m := (d + f) / 2; 5 9 7 3 8
Tri_fusion(T, d, m);
Tri_fusion(T, m + 1, f); 5 9 7 3 8
Fusion(T, d, f, m);
FinSi 5 7 9 3 8
Fin
3 5 7 8 9

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 90


…. la suite
Algorithme :
Fonction Fusion(T : Tableau, d, f, m : Entier)
Var i, j, k : Entier;
A : Tableau;
Début
Pour i := d à m Faire
A[i] := T[i];
FinPour
Pour i := (m + 1) à f Faire
A[i] := T[f-i+m+1];
FinPour
i := d; j := f; k := d;
Tant Que(i < j) Faire
Si(A[i] < A[j]) Alors { T[k] := A[i]; i++; }
Sinon { T[k] := A[j]; j--; }
FinSi
k++;
FinTQ
Fin

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 91


…. la suite
Complexité de l’algorithme Tri_Fusion: Pour déterminer la formule de
récurrence qui nous donnera la complexité de cet algorithme, nous étudions
ses trois phases « diviser pour régner » :
Diviser: cette étape se réduit au calcul du milieu de l’intervalle [p; r], sa
complexité est donc en O(1).
Régner: l’algorithme résout récursivement deux sous-problèmes de tailles
respectives n/2, d’où une complexité en 2*T(n/2).
Combiner: la complexité de cette étape est celle de l’algorithme de fusion qui
est de O(n) pour la construction d’un tableau solution de taille n.
Par conséquent, la complexité du tri_Fusion est donnée par la récurrence :
 1; si n  1

T ( n)   n
2T ( )  ( n )
 2
En utilisant le théorème de Master, la complexité de l’algorithme est en
O(nlog2 n).

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 92


3. Algorithme de Karatsuba
C’est un algorithme permettant de calculer le produit de deux grands
nombres entiers avec un temps d’exécution réduit par rapport à
l’algorithme scolaire.
Soient deux entiers x et y, ayant chacun n chiffres. On veut calculer leur
produit x × y.
On s’intéresse aux nombres de multiplications élémentaires (par pair de
chiffres).
Avec un algorithme scolaire (algorithme naïf), on effectue n2
multiplications  algorithme en (n2).
L’algorithme scolaire en mode D&R :
On divise les deux nombres x et y en deux sous-nombres, chacun ayant
n/2 chiffres :
x = a.10(n-1) + b et y = c.10(n-1)+ d
xy = ac.102(n-1) + (ad + bc).10(n-1)+ bd
Avec ce mode opératoire, on a un algorithme diviser pour régner dont
la complexité est T(n) = 4T(n/2) => T(n) = (n2)

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 93


…. la suite
Algorithme Multiplication scolaire
Fonction Multi_scolaire(x, y : Entiers ) Entier
Var a, b, c , d , m : Entiers;
Début
m:=min(size(x),size(y))-1;
Si (m = 0) alors Retourner x*y;
Sinon
p:=puissance(10,m);
a :=x/p;
b := x%p;
c :=y/p;
d :=y%p;
s0 := Multi_scolaire (a, c);
s1 := Multi_scolaire (a, d);
s2 := Multi_scolaire (b, c);
s3 := Multi_scolaire (b, d);
Retourner s0*102m+(s1+s2)*10m + s3;
FinSi
Fin

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 94


…. la suite
Amélioration de Karatsuba :
Le mathématicien A.A. Karatsuba a proposé une
amélioration de l’algorithme de multiplication en mode
D&R : la remarque qu’il a fait est la suivante : « Faire 3
multiplications pour le calcul de xy au lieu de 4 ».
Explications :
On a xy = ac.102(n-1) + (ad + bc).10(n-1)+ bd
On remarque que ad + bc = (a + b)(d + c) - ac - bd.
Alors xy= ac.10n + ((a + b)(d + c) - ac - bd).10n/2 + bd.
Cela signifie qu’au lieu de faire 4 multiplications (ac,
ad, bc et bd) on peut faire que 3 (ac, (a + b)(d + c), bd)
On diminuera la complexité de cet algorithme au lieu
d’avoir 4 appel récursif, n’utiliser que 3 (a = 3).

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 95


…. la suite
Exemple :
Pour calculer le produit 12345×6789, on choisit B = 10 et
m = 3. Puis on décompose les deux nombres comme suit :
12345 = 12 · 1000 + 345
6789 = 6 · 1000 + 789
k0 = 12 × 6 = 72
k1 = (12 + 345) × (6 + 789) = 357 × 795 = 283815
k2 = 345 × 789 = 272205
k1 - k0 - k2 = 283815 − 72 − 272205 = 11538
12345×6789 = k0 ·B2m + k1 - k0 - k2 ·Bm + k2 = 72 × 10002 +
11538 × 1000 + 272205 = 83810205.

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 96


…. la suite
Algorithme :
Fonction karatsuba(x, y : Entiers ) Entier
Var a, b, c , d , m,k0,k1,k2,p : Entiers;
Début
m=min(size(x),size(y))-1;
Si (m = 0) alors Retourner x*y;
Sinon Complexité :
T(n) = 3T(n/2).
p:=puissance(10,m);
La solution de cette équation est :
a :=x/p;
T(n) = (nlog(3)/log(2)) = (n1.59).
b := x%p;
c :=y/p;
d :=y%p;
k0 := karatsuba(a , c);
k1 := karatsuba((a +b), (c +d));
k2 := karatsuba (b , d)
Retourner k0*102m+(k1-k0-k2)*10m + k2;
FinSi
Fin

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 97


4. L'algorithme de Strassen
C’est un algorithme de type « diviser pour régner » qui permet
la multiplication de deux matrices en un temps rapide par
rapport à l’algorithme de multiplication naïf.
La multiplication de deux matrices carrées de taille n×n,
A=(aij) et B=(bij) est définie par C=A×B avec : cij = ∑ aij× bij
Algorithme diviser pour régner naïf: Nous supposerons que
n est une puissance exacte de 2. On décompose chaque
matrice en sous-matrices de taille n/2 . L'équation peut alors
se récrire C=A×B :
 C11 C12   A11 A12   B11 B12 
       
 C21 C22   A21 A22   B21 B22 
C11  A11B11  A12B21 C12  A11B12  A12B22 C21  A21B11  A22B21 C22  A21B12  A22B22

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 98


…. la suite
Fonction Multi_Matrice(A, B : Matrices) : Matrice
Var : Entiers;
Début
Si (n = 1) alors
Retourner A×B;
Sinon
C11:= Multi_Matrice(A11, B11) + Multi_Matrice(A12, B21);
C12 := Multi_Matrice(A11, B12) + Multi_Matrice(A12, B22 );
C21 := Multi_Matrice(A21, B11) + Multi_Matrice(A22 , B21);
C22 := Multi_Matrice(A21, B12) + Multi_Matrice(A22 , B22 );
FinSi
Fin
Avec cet algorithme diviser pour régner, on obtient un coût :
T(n) = 8T(n/2)+ (n2).
T(n) = (n3)

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 99


…. la suite
L'algorithme de Strassen : est un algorithme « diviser pour
régner » qui n'effectue que 7 multiplications de matrices,
contrairement à 8 de l'algorithme précédent mais qui effectue
plus d'additions et de soustractions de matrices, ce qui est sans
conséquence une addition de matrices étant « gratuite » par
rapport au coût d'une multiplication.
S1=A11(B12 - B22) S5=(A11 + A22) (B11 + B22)
S2=(A11+A12)B22 S6=(A12 - A22)(B21 + B22)
S3=(A21 +A22)B11 S7=(A11 - A21 )(B11 + B12)
S4=A22 (B21- B11)

 S5  S 4  S 2  S 6 S1  S2 
A  B   
 S3  S 4 S1  S5  S3  S7 

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 100


…. la suite
Algorithme de multiplication naïf :
Fonction Matrice_Strassen(A, B : Matrices) : Matrice
Var : Entiers;
Début
Si (n = 1) alors
Retourner A×B;
Sinon
S1 := Matrice_Strassen(A11,(B12 - B22));
S2 := Matrice_Strassen((A11+A12),B22);
S3 := Matrice_Strassen((A21 +A22),B11);
S4 := Matrice_Strassen(A22, (B21- B11));
S5 := Matrice_Strassen( (A11 + A22), (B11 + B22));
S6 := Matrice_Strassen( (A12 - A22),(B21 + B22));
S7 := Matrice_Strassen( (A11 - A21 ),(B11 + B12));
Retourner(S5 +S4 - S2 + S6 , S1 - S2 , S3 + S4 , S1 + S5 - S3 + S7);
FinSi
Fin
Avec cet algorithme diviser pour régner, on obtient un coût :
T(n) = 7T(n/2)+ (n2).
T(n) = (n2.8)

ENSAH Étude de la complexité de quelques algorithmes E.W. DADI – page : 101