IFT2015 Mikl´os Cs˝ ur¨os 25 janvier 2011

5 R´ ecursion et arbres
5.1 Nombres Fibonacci
On d´ efinit les nombres Fibonacci par F(0) = 0, F(1) = 1 et la r´ ecurrence F(n) = F(n−1)+F(n−2) (fr)
pour n > 1. Les racines de l’´ equation de r´ ecurrence homog` ene sont φ =
1+

5
2
et φ

= φ − 1 =
1−

5
2
. La
solution sp´ ecifique se trouve par la solution des ´ equations
F(0) = 0 = aφ
0
+ bφ
0

; F(1) = 1 = aφ
1
+ bφ
1

.
On obtient a = −b = 5
−1/2
, donc
F(n) =
φ
n
− φ
n


5
=
_
5
−1/2
+ o(1)
_
_
1 +

5
2
_
n
= Θ(φ
n
). (5.1)
Dans d’autres mots, F(n) a une croissance exponentielle. Comme φ
n

/

5 < 1/2 pour tout n ≥ 0 et F(n)
est entier, on voit aussi que F(n) ´ egale ` a φ
n
/

5, arrondi au plus proche entier : F(n) =
_
φ
n
/

5 + 1/2
_
.
Th´ eor` eme 5.1. L’algorithme d’Euclid (v. Exemple 4.2) prend au plus log
φ
(b) +O(1) it´ erations pour calculer le plus
grand commun diviseur entre a et b avec b ≤ a.
D´ emonstration. On d´ efinit n
i
pour i = 1, 2, . . . comme l’indice du nombre Fibonacci pour lequel F(n
i
) ≤
a < F(n
i
+ 1) au d´ ebut d’it´ eration i. Si b < F(n
i
), on a imm´ ediatement n
i+1
≤ n
i
− 1 par l’affectation
a ← b avant la prochaine it´ eration. Si b ≥ F(n
i
), alors a mod b ≤ a − b < F(n
i
− 2). Donc, apr` es
2 it´ erations, on a a < F(n
i
− 2) et n
i+2
≤ n
i
− 2. En cons´ equence, le nombre d’it´ erations est born´ e
par n
1
− 2 : avec n
i
≤ 3, on a 0 ≤ b ≤ a < 3 et l’algorithme se termine en 1 it´ eration au plus. Pour la
borne plus serr´ ee du th´ eor` eme, on consid` ere le b initiel : F(n
2
) ≤ b < F(n
2
+ 1) (affectation a ← b dans
la premi` ere it´ eration), et l’algorithme finit en n
2
− 1 it´ erations au plus. Or, n
2
=
_
log
φ
(b

5)
_
+ o(1) par
´
Equation (5.1).
REMARQUE. La borne de th´ eor` eme 5.1 montre le pire cas : c’est avec a = F(n + 1), b = F(n). Avec un tel choix, a mod b =
F(n − 1), et l’algorithme doit it´ erer n − 2 fois pour arriver ` a a = F(3) = 2, b = F(2) = 1 et se terminer apr` es une derni` ere
it´ eration de plus o` u b devient 0 et on retourne la r´ eponse a = 1.
5.2 R´ ecursion terminale
On peut toujours transformer une boucle en un algorithme r´ ecursif ´ equivalent.
IFT2015 Mikl´os Cs˝ ur¨os 19 janvier 2011
4 Analyse d’algorithmes
4.1 Temps de calcul
Pour caract´ eriser une structure de donn´ ees, on analysera souvent le temps de calcul pour les op´ erations
diff´ erentes. Typiquement, on veut arriver ` a un r´ esultat tel que «l’op´ eration search prend O(log n) temps au
pire cas» o` u n mesure la taille de la strucure. Ce qu’on veut dire par la «taille», d´ epend du contexte. Ici, n
est le nombre d’´ el´ ements dans une structure qui implante un dictionnaire. De mˆ eme fac¸on, on caract´ erisera
un algorithme en disant que «algorithme Tel-et-tel prend O(n) temps au pire cas», o` u n mesure la taille
de l’entr´ ee. En g´ en´ eral, on veut arriver ` a une borne asymptotique en fonction de la taille de l’entr´ ee et celle
de la sortie.
Exemple 4.1. On prend l’exemple de rechercher le maximum dans un tableau. L’algorithme MAX-TABLEAU
utilise une boucle. MAX-REC utilise une r´ ecurrence terminale ´ equivalente ` a la version it´ erative.
MAX-TABLEAU
`
x[0..n −1]
´
Entr´ ee : tableau x de taille n ≥ 0
Sortie : valeur maximale parmi les x[i]
B1 initialiser max ←−∞
B2 pour i ←0, . . . , n −1 faire
B3 si x[i] > max alors max ←x[i]
B4 retourner max
MAX-REC
`
x[0..n −1], i, max)
// appel initiel avec i = 0, max = −∞
Sortie : valeur maximale parmi x[i..n −1] et m
R1 si i = n alors retourner max
R2 sinon
R3 si x[i] > max alors max ←x[i]
R4 retourner MAX-REC
`
x[], i + 1, max)
Pour MAX-TABLEAU, le temps de calcul est T(n) = O(1) +
￿
O(1) + O(1) ￿

· O(n) + O(1), donc
T(n) = O(n) (v. r` egles de l’arithm´ etique avec O). L’algorithme prend un temps lin´ eaire dans la taille de
l’entr´ ee (dans tous les cas). Pour analyser le temps de calcul de MAX-REC, on a besoin de trouver la solution
` a la r´ ecurrence T(n) = O(1) +T(n −1). (Exemple 3A.4) ￿
Exercice 4.1.
´
Ecrire un algorithme it´ eratif qui calcule la somme des ´ el´ ements dans un tableau x[0..n −1]. Montrer la
version ´ equivalente avec r´ ecurrence terminale. Analyser le temps de calcul asymptotique.
4.2 La «taille» d´ epend du contexte.
En Exemple 4.1, on mesure la taille par le nombre d’´ el´ ements au lieu du nombre de bits, en supposant que
les op´ erations num´ eriques en Lignes 2 et 3 peuvent s’ex´ ecuter en un temps O(1). Mais dans une application
quelconque o` u on peut avoir des nombres entiers sans borne (pas seulement int ≤ 2
31
− 1 etc.), il faut
consid´ erer la d´ ependance du nombre de bits utilis´ es dans l’encodage de x.
Exemple 4.2. On prend l’exemple de l’algorithme d’Euclid qui trouve le plus grand commun diviseur
de deux entiers positifs.
(fr)
dans une application quelconque o` u on peut avoir des nombres entiers sans borne
(pas seulement int ≤ 2
31
−1 etc.), il faut consid´ erer la d´ ependance du nombre de
bits utilis´ es dans l’encodage de x.
Exemple 2. On prend l’exemple de l’algorithme d’Euclid qui trouve le plus grand
commun diviseur de deux entiers positifs.
E1 Algo gcd(a, b) // avec b ≤ a
E2 tandis que (b ￿= 0)
E3 c ←a mod b
E4 a ←b
E5 b ←c
E6 retourner a
Le temps de calcul est polynomiel dans la taille de l’entr´ ee.
Preuve : On a a = kb + c ≥ (k + 1)c ≥ 2c en Ligne E3. Donc bc ≤ ab/2. Par
cons´ equence, le nombre d’it´ erations est born´ e par lg(ab) = lg a + lg b. Si a mod b
prend O(log
2
a) temps, alors l’ex´ ecution est en temps O(log
3
a). ￿

2
Taille de l'entrée est lg a + lg b bits.
O(log b)
O(log a+log b) fois
O(log^2 a)
O(log a)
O(log b)
O(log c)
1
Les variables locales
(incluant la variable
d'itérations)
deviennent des
arguments dans la
version récursive
cas
terminal
= fin de la
boucle
mise à jour de la
variable de la
boucle
appel récursif en position terminale
1
L’appel r´ ecursif est en position terminale : on n’a pas besoin d’attendre le retour de l’appel, donc on (fr)
peut simplement transf´ erer le contrˆ ole d’ex´ ecution ` a l’appel execut´ e. Plut ˆ ot qu’allouer de nouvelle espace
sur la pile d’ex´ ecution, on peut remplacer le bloc allou´ e pour les variables locales et adresse de retour. En
cons´ equence, la pile d’ex´ ecution ne d´ eborde pas. Ce remplacement est en fait l’´ equivalent de transformer la
r´ ecurrence en une it´ eration, perform´ e automatiquement par des compilateurs modernes.
L’appel r´ ecursif est en position terminale : on n’a pas besoin d’attendre le retour de l’appel, donc on
peut simplement transf´ erer le contrˆ ole d’ex´ ecution ` a l’appel execut´ e. Plut ˆ ot qu’allouer de nouvelle espace
sur la pile d’ex´ ecution, on peut remplacer le bloc allou´ e pour les variables locales et adresse de retour. En
cons´ equence, la pile d’ex´ ecution ne d´ eborde pas.
MAX-REC2 ￿

x[0..n −1], i)
Sortie : valeur maximale parmi x[i..n −1]
R1 si i = n alors retourner −∞
R2 sinon retourner max ￿

x[i], MAX-REC2(x, i + 1) ￿

5.3 Diviser pour r´ egner
5.4 Structures r´ ecursives
Liste chaˆın´ ee, arbre, parcours
niveau 0
niveau 1
niveau 2
niveau 3
hauteur=2
hauteur=3
Niveau d’un nœud u : longueur du chemin qui
m` ene ` a u ` a partir de la racine
Hauteur d’un nœud u : longueur du chemin ` a la
feuille la plus distante dans le sous-arbre de u
Hauteur de l’arbre : hauteur de la racine
Longueur du chemin (interne/externe) :
somme des niveaux de tous les nœuds
(internes/externes)
5.5 Parcours d’arbres
5.6 Repr´ esentation d’un arbre numerot´ e
Arbre = ensemble d’objets repr´ esentant de nœuds + relations parent-enfant. En g´ en´ eral, on veut retrouver
facilement le parent et les enfants de n’importe quel nœud.
public class TreeNode
{
TreeNode parent;
TreeNode enfant_gauche;
TreeNode enfant_droit;
// ... d’autre information
}
Si l’arbre est d’arit´ e k, alors on peut avoir TreeNode[] enfants avec enfants.length = k.
A
D E
I J K F G H
L M N
B C
fils gauche
frère droit
Si l’arit´ e de l’arbre n’est pas connu en avance (ou la
plupart des nœuds ont tr` es peu d’enfants), on peut
utiliser une liste pour stocker les enfants : c’est la
repr´ esentation fils-gauche, fr` ere-droit (first-child,
next-sibling)
2
appel récursif n'est pas en position terminale:
il faut attendre la valeur retournée
par l'appel récursif
pour évaluer l'expression max{...}
Si on se sert de la valeur retourn´ ee par
l’appel r´ ecursif dans le calcul, il faut al-
louer un nouveau bloc d’activation pour
chaque appel sur la pile.
5.3 Diviser pour r´ egner
Un principe g´ en´ eral dans la conception d’algorithmes r´ ecursif est celui de diviser pour r´ egner (divide
and conquer). La d´ emarche g´ en´ erale est (1) couper le probl` eme dans des sous-probl` emes similaires, (2) appel
r´ ecursif pour r´ esoudre les sous-probl` emes, (3) combinaison des r´ esultats des sous-probl` emes.
MAX-MIN
_
x[0..n − 1], g, d) // trouve le max et min parmi x[g..d − 1]
// appel initiel avec g = 0, d = n
MM1 si d − g = 0 alors retourner (−∞, ∞)
MM2 si d − g = 1 alors retourner (x[g], x[g])
MM3 si d − g = 2 alors
MM4 si x[g] < x[g + 1] alors retourner (x[g + 1], x[g]) sinon retourner (x[g], x[g + 1])
MM5 mid ←
_
(g + d)/2
_
// (diviser)
MM6 (max
1
, min
1
) ← MAX-MIN(x, g, mid) ; (max
2
, min
2
) ← MAX-MIN(x, mid, d)
MM7 si max
1
> max
2
alors max ← max
1
sinon max ← max
2
MM8 si min
1
< min
2
alors min ← min
1
sinon min ← min
2
MM9 retourner (max, min)
Le temps de calcul de l’algorithme MAX-MIN s’´ ecrit par la r´ ecurrence
T(n) = T(n/2) + T(n/2) + Θ(1) {n > 2} (5.2)
Th´ eor` eme 5.2. La solution de l’
´
Equation (5.2) est T(n) = Θ(n).
Exercice 5.1. D´ emontrer Th´ eor` eme 5.2.
Exercice 5.2. Donner le nombre exact de comparaisons (Lignes MM4, MM7, MM8) dans l’algorithme MAX-MIN.
2

peut simplement transf´ rer le contrˆ le d’ex´ cution a l’appel execut´ . arbre. on peut remplacer le bloc allou´ pour les variables locales et adresse de retour.1. M AX . (3) combinaison des r´ sultats des sous-probl` mes.MIN(x.n − 1].. mid. En e e cons´ quence. e e next-sibling) l’algorithme M AX . d = n Hauteur de l’arbre : hauteur de la racine hauteur=3 hauteur=2 niveau 2 MM1 si d − g = 0 alors retourner (−∞... g. le parent et les enfants de n’importe max ← max1 sinon max ← max2 MM8 si min < min2 alors min ← min1 sinon min ← min2 public class TreeNode 1 { MM9 retourner (max.} l’appel r´ cursif dans le calcul. i + 1) L’appel r´ cursif est en position terminale : on n’a pas besoin d’attendre le retour de l’appel.length = k. // . R2 sinon retourner max x[i]. d) Arbre = ensemble d’objets repr´ sentant de nœuds + relations parent-enfant. la pile d’ex´ cution ne d´ borde pas. e ´ Th´ or` me 5. mid) . e e e ` (fr) 5. i) pour évaluer l'expression max{. perform´ automatiquement par des compilateurs modernes. 2 2 . min) TreeNode parent.g´ n´ ral ı e Un principe parcours e e ` Hauteur d’un nœud u : longueur du chemin a la Le temps de calcul de l’algorithme M AX . g. on veut retrouver e e e facilement MM7 si max1 > max2 alors quel nœud.MIN x[0. TreeNode enfant_droit.REC 2 x[0. alors on peut avoir TreeNode[] enfants avec enfants.MIN s’´ crit par la r´ currence e e T (n) = T ( n/2 ) + T ( n/2 ) + Θ(1) {n > 2} (5. Plutˆ t qu’allouer de nouvelle espace e o e e o sur la pile d’ex´ cution.. En g´ n´ ral. MM7.6 Repr´ sentation d’un arbre numerot´ e e MM6 (max1 . D´montrer Th´or`me 5. e e Exercice 5.n − 1].MIN(x..REC 2(x. fr` re-droit (first-child. donc on e ` peut simplement transf´ rer le contrˆ le d’ex´ cution a l’appel execut´ . e e frère droit e B F C D I E J A fils gauche Exercice 5. e e e e e M AX . x[g]) des niveaux de tous les nœuds (internes/externes) MM3 si d − g = 2 alors MM4 si x[g] < x[g + 1] alors retourner (x[g + 1]. (2) appel e e e m` ne a u a partir de la racine e ` ` r´ cursif pour r´ soudre les sous-probl` mes. (max2 . min2 ) ← M AX .d − 1] de u feuille la et distante dans le sous-arbre niveau 1 // appel initiel avec g = 0.2.MIN.2) est T (n) = Θ(n)..2) } Si l’arbre est d’arit´ k..3 5. donc on e r´ currence en une it´ ration. on peut remplacer le bloc allou´ pour les variables locales et adresse de retour. d) // trouve le maxplusmin parmi x[g. Ce remplacement est en fait l’´ quivalent de transformer la e e e e L’appel r´ cursif est en position terminale : on n’a pas besoin d’attendre le retour de l’appel.3 Diviserecursives e 5.2. x[g + 1]) 5. La solution de l’Equation (5. MM8) dans repr´ sentation fils-gauche.2. Donner le nombre exact de G H L K M N Si l’arit´ de l’arbre n’est pas connu en avance (ou la e plupart des nœuds ont tr` s peu d’enfants). min1 ) ← M AX . Plutˆ t qu’allouer de nouvelle espace e o e e o sur la pile d’ex´ cution. En e e pas en position terminale: appel récursif n'est cons´ quence. on peut e utiliser une liste pour stocker les enfants : c’est la comparaisons (Lignes MM4. e e e il faut attendre la valeur retournée Si on se sert de la valeur retourn´ e par e par l'appel récursif ￿ M AX . TreeNode enfant_gauche. il faut ale Sortie : valeur maximale parmi x[i.4 Structures r´ pour r´ gner dans la conception d’algorithmes r´ cursif est celui de diviser pour r´ gner (divide e e Niveau le nœude u : dans des chemin qui e and conquer).5 Parcours d’arbres MM5 mid ← (g + d)/2 // (diviser) 5. x[g]) sinon retourner (x[g]. d’autre information niveau 0 Diviser pour r´ gner e Liste chaˆn´ e.. ∞) du chemin (interne/externe) : Longueur niveau 3 somme MM2 si d − g = 1 alors retourner (x[g].n − 1] louer un nouveau bloc d’activation pour R1 si i = n alors retourner −∞ ￿ ￿ chaque appel sur la pile. La d´ marche g´ n´ rale est (1) couper d’unprobl` me longueur du sous-probl` mes similaires. la pile d’ex´ cution ne d´ borde pas.

Sign up to vote on this title
UsefulNot useful

Master Your Semester with Scribd & The New York Times

Special offer for students: Only $4.99/month.

Master Your Semester with a Special Offer from Scribd & The New York Times

Cancel anytime.