0% ont trouvé ce document utile (0 vote)
47 vues30 pages

Handout 2

Transféré par

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

Handout 2

Transféré par

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

Algorithmes Récursifs

Algorithmes Récursifs 1 / 29
Règles de calculs : combinaisons des complexités

Les instructions de base prennent un temps constant, noté O(1) ;

On additionne les complexités d’opérations en séquence :

O(f (n)) + O(g (n)) = O(f (n) + g (n))

Même chose pour les branchements conditionnels :

max(O(f (n)), O(g (n))) = O(f (n)) + O(g (n))

Exemple

si <condition> alors O(g (n)) 
#instructions (1); O(f1 (n))

= O(g (n) + f1 (n) + f2 (n))
sinon 

#instructions (2); O(f2 (n))

Algorithmes Récursifs 2 / 29
Règles de calculs : combinaison des complexité

Dans les boucles, on multiplie la complexité du corps de la boucle par le nombre


d’itérations ;

Algorithmes Récursifs 3 / 29
Règles de calculs : combinaison des complexité

Dans les boucles, on multiplie la complexité du corps de la boucle par le nombre


d’itérations ;

Calcul de la complexité d’une boucle while :

Exemple
en supposant qu’on a O(h(n)) itérations
tant que <condition> 
faire O(g (n))
= O(h(n) × (g (n) + f (n)))
#instructions ; O(f (n))

Algorithmes Récursifs 3 / 29
Règles de calculs : combinaison des complexité

Dans les boucles, on multiplie la complexité du corps de la boucle par le nombre


d’itérations ;

Calcul de la complexité d’une boucle for :

Exemple

pour i allant de a à b faire



#instructions ; = O((b − a + 1) × f (n))
O(f (n))

Algorithmes Récursifs 3 / 29
Calcul de la complexité asymptotique d’un
algorithme

Pour calculer la complexité d’un algorithme :

1 on calcule la complexité de chaque “partie” de l’algorithme ;

2 on combine ces complexités conformément aux règles qu’on vient de voir ;

3 on simplifie le résultat grâce aux règles de simplifications qu’on a vues ;


F élimination des constantes, et
F conservation du (des) termes dominants

Algorithmes Récursifs 4 / 29
Exemple : calcul de la factorielle de n ∈ N

Reprenons le calcul de la factorielle, qui nécessitait 3n opérations :

Algorithme : Factorielle(n)
nombre coût
Données : un entier n
Résultat : un entier valant n!
1 fact, i : entier;
2 début
3 fact ← 2; initialisation : Θ(1)× Θ(1)
4 pour i allant de 3 à n faire itérations : Θ(n)× Θ(1)
5 fact ← fact ∗ i; mult. + affect. : Θ(n)× Θ(1)
6 retourner fact; retour fonction : Θ(1)× Θ(1)

Nombre total d’opérations :

Θ(1) + Θ(n) ∗ Θ(1) + Θ(n) ∗ Θ(1) + Θ(1) = Θ(n)

Algorithmes Récursifs 5 / 29
Exemple : Tri à bulles

La méthode de “comptage” n’est pas toujours applicable directement

Algorithme : TriBulles(T )
nombre coût
Données : un tableau T
Résultat : le tableau T trié
1 début
2 pour i allant de 2 à |T | faire itérations : Θ(|T |)× Θ(1)
3 pour j allant de 1 à i − 1 faire itération : ?× Θ(1)
4 si T [j + 1] < T [j] alors 1ère itération : 1 comparaison
5 échanger(T [j + 1], T [j]); 2ème itération : 2 comparaisons
...

Séries arithmétiques
n
X 1
k = 1 + 2 + 3 + ··· + n = n(n + 1) ∈ Θ(n2 )
2
k=1

Nombre total d’opérations : Θ(|T |2 )


Algorithmes Récursifs 6 / 29
Récurrences

Algorithme : Fusion(T1,T2)
Stratégie “diviser pour régner” Données : deux tableaux T 1 et T 2
Résultat : un tableau T trié contenant les
éléments de T 1 et de T 2
Algorithme : TriFusion(T ) T : tableau de taille T 1 + T 2;
Données : un tableau T début
Résultat : le tableau T trié si |T 1| = 0 alors
mil : entier; T ← T 2;
début sinon si |T 2| = 0 alors
si |T | ≤ 1 alors T ← T 1;
retourner T ; sinon si T 1[1] < T 2[1] alors
sinon T [1] ← T 1[1];
|T |+1
milieu ← b 2 c; T [2:] ← Fusion(T 1[2:], T 2[1:]);
retourner sinon
Fusion(T [:mil] , T [mil:]); T [1] ← T 2[1];
T [2:] ← Fusion(T 1[1:], T 2[2:]);
retourner T

Algorithmes Récursifs 7 / 29
Illustration du Tri Fusion

Algorithmes Récursifs 8 / 29
Récurrences

Temps d’exécution T dans le pire des cas du tri fusion pour trier un tableau de n
entiers

(
Θ(1) si n = 1
T (n) =
2T (n/2) + Θ(n) si n > 1

Complexité du tri fusion : T (n) = Θ(n log n)

Comment passer de l’un à l’autre ?


I Méthode par substitution
I Méthode générale (théorème maître)

Algorithmes Récursifs 9 / 29
Méthode par substitution

Il faut avoir une intuition sur la forme de la solution (ici : O(n log n))

On veut montrer que T (n) = 2T (bn/2c) + Θ(n) ∈ O(n log n)

On montre par induction qu’il existe f (n) t.q. ∀n T (n) ≤ f (n)


I On va en déduire a posteriori que T (n) ∈ O(f (n))

Attention !
L’hypothèse d’induction est T (n) ≤ f (n), et non T (n) ∈ O(f (n))
L’argument inductif “pour tout x < n, T (x) ∈ O(f (x))” ne veut pas dire grand chose
puisque la notation O est définie pour n arbitrairement grand : on remplace tous les
termes en O, Ω, Θ par une fonction élément de l’ensemble

Algorithmes Récursifs 10 / 29
Méthode par substitution (condition aux limites)

T (n) = 2T (bn/2c) + n ≤ cn log n

Il faut montrer que la formule est vraie pour les conditions limites de la récurrence
pour des données de petite taille, i.e. n = 1

Problème : c’est faux pour n = 1 car c × 1 × log 1 = 0 < T (1) = 1 ;

Mais on cherche à montrer la complexité pour des données de grande taille : n ≥ n0


et on a le choix pour n0 =⇒ vérifier pour T (2) (et T (3))

On peut aussi borner par f (n) = cn log n + b puisque cn log n + b ∈ O(n log n)
I Ou même f (n) = cn log n + an + b

Algorithmes Récursifs 11 / 29
Méthode par substitution (condition aux limites)

T (n) = 2T (bn/2c) + n ≤ cn log n

On vérifie que la formule tient pour T (2) et T (3)

T (2) = 2T (b2/2c) + 2

T (2) = 2T (1) + 2

T (2) = 2 ∗ 1 + 2 = 4 ≤ 2c log 2 = 2c

T (2) = 4 ≤ 2c

c≥2
On fait la même chose pour T (3)...
... et on obtient que c doit être ≥ 2.
Algorithmes Récursifs 12 / 29
Méthode par substitution (Induction)

T (n) = 2T (bn/2c) + n ≤ cn log n

On suppose maintenant que T (x) ≤ cx log x est vrai pour tout 2 ≤ x ≤ n − 1 ; et on


vérifie que c’est aussi le cas pour x = n
T (bn/2c) ≤ cbn/2c logbn/2c

On substitue dans l’expression

T (n) = 2T (bn/2c) + n
≤ 2cb 2n c log(b 2n c) + n
≤ cn log(n/2) + n
= cn log n − cn log 2 + n
= cn log n − cn + n
≤ cn log n

A condition que c ≥ 1 (on prendra c ≥ 2, à cause de T (2) et T (3))

Algorithmes Récursifs 13 / 29
Méthode générale

Pour les récurrence de la forme T (n) = aT (n/b) + f (n) avec a ≥ 1 et b > 1

L’algorithme découpe la donnée en a sous-problèmes de taille n/b et les résout


récursivement
La fonction f représente le coût de division et de « fusion » du problème.

Exemple pour le tri fusion : a = 2, b = 2 et f (n) = Θ(n)

Exemple pour la recherche binaire : a = 1, b = 2 et f (n) = Θ(1)

Il existe un théorème pour calculer la complexité : le théorème maître

Algorithmes Récursifs 14 / 29
Théorème maître (général) - version simplifiée

On ne considère que les récurrences T (n) = aT (n/b) + Θ(nd ) (ou O(nd ))


avec a ≥ 1, b > 1, d ≥ 0

1 Si d > logb a, T (n) = Θ(nd ) complexité dominée par le coût de fusion


2 Si d < logb a, T (n) = Θ(nlogb a ) complexité dominée par le coût du sous-problème
3 Si d = logb a, T (n) = Θ(nd log n) pas de domination

Tri fusion : (
Θ(1) si n = 1
T (n) =
2T (n/2) + Θ(n) si n > 1

a = 2, b = 2, d = 1, log2 2 = 1 = d

On est donc dans le cas 3 et la complexité en Θ(n log n)

Algorithmes Récursifs 15 / 29
Théorème maître (général) - version simplifiée

On ne considère que les récurrences T (n) = aT (n/b) + Θ(nd ) (ou O(nd ))


avec a ≥ 1, b > 1, d ≥ 0

1 Si d > logb a, T (n) = Θ(nd ) complexité dominée par le coût de fusion


2 Si d < logb a, T (n) = Θ(nlogb a ) complexité dominée par le coût du sous-problème
3 Si d = logb a, T (n) = Θ(nd log n) pas de domination

Recherche binaire : (
Θ(1) si n = 1
T (n) =
T (n/2) + Θ(1) si n > 1

a = 1, b = 2, d = 0, log2 1 = 0 = d

On est donc dans le cas 3 et la complexité en Θ(log n)

Algorithmes Récursifs 16 / 29
Taille de la Donnée

Taille de la Donnée 17 / 29
La taille de la donnée

Taille de la donnée |x|


Espace mémoire nécessaire pour la représenter x
Dans une unité quelconque, fonction de la donnée : |x| ∈ Θ(f (x))

Type primitif entier, flottant, etc. sur 32 ou 64 bits : Θ(1)


Entier non-borné x : |x| ∈ Θ(log x)
Liste L de n caractères : |L| ∈ Θ(n)

Taille de la Donnée 18 / 29
La taille de la donnée : exemple

La complexité se mesure en fonction de la taille de la donnée


Parfois, on mesure plus facilement la complexité d’un algorithme en fonction d’un
autre paramètre que la taille de la donnée (ex : sa valeur)
Si l’algorithme A est en Θ(f (x)) pour une donnée x et la taille |x| est en Θ(g (x)),
alors la complexité de A sera en Θ(f (g −1 (x)))
Exemple

Algorithme : Carré(x)
Données : un entier x Complexité : Θ(x 2 )
Résultat : un entier valant x 2
r : entier;
début Mais la taille de la donnée est |x| = Θ(log x)
r ← 0;
pour i allant de 1 à x faire
Autrement dit, x = Θ(2|x| )
pour j allant de 1 à x faire
r ← r + 1;
cet algorithme est donc en Θ(22|x| )
retourner r ;
(exponentiel !)

Taille de la Donnée 19 / 29
La taille d’une structures de données

Dans le cas de structures de données (listes, ensembles, etc.) il faut analyser la


structure : la taille de chaque élément, les pointeurs, etc.

Exemple, liste L de n éléments


Il faut Θ(1) bits
P par élément, plus la somme des tailles des éléments : donc
|L| ∈ Θ(n) + e∈ |e| ⊆ Θ(n) × Θ(|e|)
Les éléments sont des entiers : |L| ∈ Θ(n)
Les éléments sont des entiers non bornés et m est l’élément maximum :
|L| ∈ Θ(n log m)

Taille de la Donnée 20 / 29
La taille d’une structures de données

La taille des structures va dépendre de leur codage :

Exemple, graphe G = (S, A)


Tableau de tableaux : Il faut Θ(1) bits par arc potentiel, donc
|G | ∈ Θ(|S|2 )
Listes d’adjacence : Il faut Θ(log |S|) bits par arc dans A, donc
|G | ∈ Θ(|A| log |S|)

Taille de la Donnée 21 / 29
La taille de la donnée

Attention : sujet piégeux !


Taille d’une liste de n entiers (codés sur 32 bits) : Θ(n)
Taille d’une liste de n entiers (où l’élément maximum est m) : Θ(n log m)
Taille d’un ensemble de n entiers (codés sur 32 bits) : Θ(1) ! !
I Il y a un nombre fini d’entiers représentable avec 32 bits (232 ), et donc un nombre fini
32
d’ensembles de tels entiers (22 )

Taille de la Donnée 22 / 29
Classes de Problèmes

Classes de Problèmes 23 / 29
Vocabulaire

Un algorithme est dit :

en temps constant si sa complexité (dans le pire des cas) est bornée par une constante

linéaire (resp. linéairement borné) si sa complexité (dans le pire des cas) est Θ(n)
(resp. O(n))

quadratique (resp. au plus quadratique) si sa complexité (dans le pire des cas) est
Θ(n2 ) (resp. O(n2 ))

polynômial ou polynômialement borné, si sa complexité (dans le pire des cas) est en


O(np ) pour un certain p > 0

c
(au plus) exponentiel si elle est en O(2n ) pour un certain c > 0

Classes de Problèmes 24 / 29
Classes de problèmes

Analyser la complexité des algorithmes permet de faire un choix éclairé, mais pas
seulement

Classer les problèmes


I en fonction de la complexité du meilleur algorithme connu pour les résoudre

TIME (f (n))
Ensemble des problèmes pour lesquels il existe un algorithme en O(f (n))

Tri ∈ TIME(n log n)


Recherche dans un tableau trié ∈ TIME(log n)
Tout algorithme de tri est en Ω(n log n) =⇒ Tri 6∈ TIME(n)
Trier est plus “difficile” que chercher dans un tableau trié

Classes de Problèmes 25 / 29
Classes de problèmes (suite)

On peut analyser l’espace mémoire utilisé par un algorithme de manière similaire

SPACE (f (n))
Ensemble des problèmes pour lesquels il existe un algorithme nécessitant
O(f (n)) octets

On ne compte pas la taille de la donnée, mais on compte la taille de la réponse

Théorème
TIME(f (n)) ⊆ SPACE(f (n))

Problème A ∈ TIME(f (n)) =⇒ A ∈ SPACE(f (n))


Chaque octet utilisé implique Ω(1) opération(s)

Classes de Problèmes 26 / 29
Parcours de Graham

Trouver l’enveloppe convexe d’un 2


ensemble de points
6
8

Algorithme
4
1 Trouver le point p de plus petite
ordonnée O(n)
5
2 Trier les autres points en fonction de 9
l’angle avec l’axe des abcisses par
rapport à p 7
1
3 Appliquer le parcours de Graham O(n)
10
I retour arrière en cas de “tournant à
droite”

Classes de Problèmes 28 / 29
Réduction polynômiale

On peut trouver l’enveloppe convexe en O(n) plus le coût de trier n entiers

Tri ∈ TIME(n log n) =⇒ Enveloppe convexe ∈ TIME(n log n)

Réduction de Enveloppe convexe vers Tri :


I Enveloppe convexe pas plus difficile que Tri
I Tri au moins aussi difficile que Enveloppe convexe

Réduction polynômiale de A vers B (de Cook / de Turing) :


Un algorithme pour résoudre A en O(nc ) (pour c un constante et n la taille
de la donnée) sous l’hypothèse que le problème B peut être résolu en Θ(1)

Classes de Problèmes 29 / 29

Vous aimerez peut-être aussi