Vous êtes sur la page 1sur 8

Universit Paris Diderot Paris 7

L3 Informatique

Algorithmique
Anne 2010-2011, 1er semestre

TD n2
Arbres Binaire de Recherche
Le type de donn arbre" sera utilis pour indiquer lensemble de toutes les Arbres Binaires tiquets
(ABEs) par des cls de type entier. La taille de un ABE a est par dfinition le nombre de cls contenues
dans a. Nous rappelons que un Arbres Binaire de Recherche (ABR) a est un ABE tel que tout nud
interne b de a contient un cl
suprieure ou gale toutes le cls contenues dans le sous-arbre gauche de b ;
infrieure strictement toutes le cls contenues dans le sous-arbre droit de b.
Exercice 1 Est-ce que on peut utiliser la procdure suivante pour tester si un ABE a est un ABR ?
1
2
3
4

Fonction estABR(a : arbre) : boolen


dbut
si (estVide(a)) alors
retourner vrai;
si (estVide(G(a))) alors
gauche := cl(a);

5
6

sinon
gauche := cl(G(a));

7
8

si (estVide(D(a))) alors
droite := cl(a);

9
10

sinon
droite := cl(D(a));

11
12

retourner (gauche cl(a) droite estABR(G(a)) estABR(D(a)));

13
14

fin

Sinon crivez une fonction qui teste si un ABE a est un ABR.


Pour un tableau A[1, . . . , n] la dfinition de k-me lment" est trs simple comprendre et laccs au
k-me lment est une opration lmentaire (cest dire, avec complexit (1)). Au contraire un arbre
binaire nest pas une structure linaire et nous pouvons definire plusieur notions de k-me lment",
selon la facon dans laquelle nous parcourons larbre.

tant donn un ABE quelconque on choisit la faon suivante de numroter les nuds de larbre :

Fig. 1 Numrotation des nuds dun ABE

Exercice 2 [Accs au k-me lment] Soit a un ABR.


Question 1. Proposez une mthode pour retourner le k-me lment de a en utilisant :
une procdure VisiteGRD(a : arbre) qui parcourt compltement larbre a.
un tableau dentiers T .
Quelle est la complexit de cette mthode en fonction de la taille de a ?
Question 2. En supposant davoir disposition le type de donne boolen entier, proposez une
fonction RecherchePos(a : arbre, k : entier) : boolenentier telle que si (b, n) = RecherchePos(a, k)
alors
si la taille de a est infrieure k alors b = faux et n est la taille de a ;
si la taille de a nest pas infrieure k alors b = vrai et n est la valeur de la k-me cl.
Quelle est la complexit de cette mthode ?
Question 3. En supposant quon dispose dune fonction taille(a : arbre) : entier calculant la taille
dun arbre a en (1), proposez une fonction RecherchePos(a : arbre, k : entier) : arbre telle que si
b = RecherchePos(a, k) alors
si taille(a) < n, alors b = ArbreVide() ;
si taille(a) n, alors cl(b) est la k-me cl dans larbre a.
valuez la complexit de la procdure en fonction de la hauteur de larbre a.
Question 4. En acceptant de modifier lgrement la structure des ABRs, pouvez-vous proposer une
fonction taille(a : arbre) : entier ayant complexit (1) ? Vrifierez que votre modification ne change
pas la complexit des fonctions dinsertion et de suppression dun nud dans un ABR.

Exercice 3 [Recherche du successeur] Modifiez lgrment la dfinition de ABR de telle sorte que
toutes les cls soyent distinctes. On appelle strict un ABR qui satisfait cette dfinition. Soit a un ABR
strict. Le successeur de un nud x (sil existe) est par dfinition le nud y ayant la plus petit cl entre
le cls plus grand que cl(x).
Question 1. Montrer rigoureusement que dans a :
(a) llment minimum se trouve un nud sans fils gauche.
(b) si un nud a un fils droit, son successeur est le minimum de son sous arbre droit. En dduire que
si un nud a un fils droit, alors son successeur na pas de fils gauche.
(c) si un nud na pas de fils droit, son successeur, sil existe, est le premier de ses anctres dont le fils
gauche est aussi lun de ses anctres.
Question 2. crire une fonction succ(b : arbre) : arbre qui retourne le sous arbre de a dont la racine
est le successeur de b. Quelle est la complexit en temps de cet algorithme ?
2

Exercice 4 Soit a un ABR strict, soient x un nud feuille et y son parent. Montrer que cl(x) est soit
la plus petite cl de a suprieure cl(y), soit la plus grande cl de a infrieure cl(y).

Exercice 5 On peut trier un tableau T de nombres entiers en commenant par construire par insertions
successives un ABR contenant ces nombres puis en effectuant un parcours infixe de larbre. Quels sont
les temps dexcution de cet algorithme en fonction de la taille de T dans le pire et dans le meilleur des
cas ?

Exercice 6 [Insertion la racine] Dans un arbre binaire de recherche, avec la mthode dinsertion
classique, toutes les nouvelles valeurs sont places aux feuilles de larbre. Si lon souhaite accder un
nud insr rcemment dans larbre, il faudra parcourir toute la hauteur de larbre. Dans certaines
applications, on souhaite accder plus frquemment aux derniers lments insrs. Il sagit du principe
LRU 1 . Dans ce cas particulier, il peut tre intressant dinsrer la racine. En procdant de la sorte, les
valeurs auxquelles on souhaite accder le plus souvent ont plus de chance dtre une faible profondeur.
En considrant lexemple de la figure 2 :
Question 1. Tracez le chemin qui va de la racine au nud o classiquement il faudrait insrer le nud
33.
Question 2. partir des rponses aux questions prcdentes, proposez une procdure insertionRacine(a :
arbre, k : entier) dinsertion la racine dans un ABR.
valuer la complexit de cet algorithme dans le pire des cas.

Fig. 2 un arbre binaire de recherche

1 pour

Least Recently Used !

Solutions

Solution 1 Lalgorithme nest pas correct. Par exemple larbre (2 < 3 > 5) < 4 > 5 nest pas
un ABR. Un bon algorithme est, par exemple :
1
2
3
4

Fonction estABR(a : arbre) : boolen


dbut
si (estVide(a)) alors
retourner vrai;
si (estVide(G(a))) alors
gauche := cl(a);

5
6

sinon
gauche := max(G(a));
// calcule la cl maximum de larbre

7
8
9

si (estVide(D(a))) alors
droite := cl(a) + 1;

10
11

14

sinon
droite := min(D(a));
// calcule la cl minimum de larbre

15

retourner (gauche cl(a) < droite estABR(G(a)) estABR(D(a)));

12
13

16

fin

Solution 2
Rponse 1.
1
2
3
4
5
6

1
2
3
4
5
6
7

Fonction main(a : arbre, k : entier) : entier


dbut
i := 1;
VisiteGRD(a);
retourner T [k];
fin
Procdure VisiteGRD(a : arbre)
dbut
si (estVide(a)) alors
VisiteGRD(G(a));
T [i] := cl(a);
i := i + 1;
VisiteGRD(D(a));
retourner;

8
9

fin

Cette mthode est en (n).


Rponse 2.

1
2
3
4

Fonction RecherchePos(a : arbre, k : entier) : boolen entier


dbut
si (estVide(a)) alors
retourner (faux, 0);
(b, n) := RecherchePos(G(a), k);
si (b = vrai) alors
retourner (vrai, n);

5
6
7

sinon
si (k = n + 1) alors
retourner (vrai, cl(a));

8
9
10

sinon
(b0 , n0 ) := RecherchePos(D(a), k n 1);
si (b0 = vrai) alors
retourner (vrai, n0 );

11
12
13
14

sinon
retourner (faux, n + n0 + 10 );

15
16

17

fin

La complexit de la fonction RecherchePos est (k).


Rponse 3. On remarque quil est ncessaire de parcourir la branche gauche dun arbre uniquement si
k est suprieur au nombre de nuds du fils-gauche. Une possibilit est donc de calculer pralablement la
taille de fils gauche avant de dcider si on effectue la recherche gauche ou droite.
1
2
3
4
5
6
7

Fonction RecherchePos(a : arbre, k : entier) : arbre


dbut
tailleF G := taille(G(a));
tailleF D := taille(D(a));
si (tailleF G + tailleF D + 1 < k) alors
retourner arbreVide();
// la position k nest pas dans larbre
si (tailleF G = k 1) alors
retourner a;
// la position k est le noeud courant

8
9
10

si (tailleF G < k) alors


retourner RecherchePos(G(a), k);
// la position k est dans le sous-arbre gauche

11
12
13

sinon
retourner RecherchePos(D(a), k tailleF G 1);
// la position k est dans le sous-arbre droit

14
15
16
17

fin

Le nombre maximum dappel rcursif de la fonction RecherchePos tant h, la hauteur de larbre, on


pourrait dire navement que la complexit dans le pire cas de cet algorithme est O(h). Ce nest le cas que
si la fonction taille est en (1).
Or, normalement une fonction taille pour les ABR est en (n) (o n est la taille de larbre). Dans le
cas o lon recherche le prmier lment dun arbre de taille n compltement dsquilibr gauche, la
complexit de la fonction RecherchePos est en ralit O(n2 ). Cela se vrifie par rcursion sur la taille de
larbre.

Rponse 4. La seule manire dobtenir une fonction taille en (1) est de modifier la structure de
larbre pour que chaque nud stocke sa taille.
Pour que cette information sur la taille reste cohrente, il faut modifier les fonction dinsertion et de
suppression. Ces modifications peuvent tre faites sans changer leur complexits respectives.
Lors de linsertion il suffit de rajouter sur le chemin du nouveau nud jusq la racine 1 la taille de
chaque arbre. On peut aisment voir que lorsquon ajoute un nud un ABR, on augmente la taille de
1 rcursivement sur les sous-arbres concerns. Incrmenter O(h) compteurs, se fait en temps constant
sur chaque nud donc la complexit reste O(h).
Concernant la suppression, en utilisant la mthode de suppression qui utilise le successeur, il faut
dcrmenter de 1 la taille de tout les nuds allant de la racine lancienne position du successeur.
La nouvelle taille de la racine est lancienne taille 1. Dcrmenter O(h) compteur, se fait en temps
constant sur chaque nud donc la complexit rest O(h).

Solution 3 Un ABR strict a est un ABE tel que tout nud interne b de a contient un cl
suprieure strictement toutes le cls contenues dans le sous-arbre gauche de b ;
infrieure strictement toutes le cls contenues dans le sous-arbre droit de b.
Rponse 5.
(a) Soit un nud x avec un fils gauche y, on a cl(y) < cl. Donc x ne contient pas la cl minimale.
Par contrapose, on en dduit que la cl minimale est situe sur un nud sans fils gauche.
(b) Soit un nud x avec un fils droit. On note dabord que succ(x) existe puisque D(x) a une cl
plus grand que cl(x). Puis on montre que succ(x) est dans le sous arbre droit de x. Cest clair
que succ(x) 6= x et que succ(x) nest pas dans le sous arbre gauche de x. En effet, soit succ(x)
un nud que na pas pour anctre x. Alors x et succ(x) ont un premier anctre commun u 6= x.
Si u = succ(x) alors forcement x, D(x) sont dans le sous arbre gauche de succ(x), mais alors
cl(x) < cl(D(x)) < cl(succ(x)) : a est en contradiction avec lhypothse que succ(x) est le
successeur de x dans a. Donc forcement u 6= succ(x) et x est dans le sous arbre gauche de u et
succ(x) est dans le sous arbre droit de u. Mais alors cl(x) < cl(u) < cl(succ(x)) : a est en
contradiction avec lhypothse que succ(x) est le successeur de x dans a.
La seule possibilit est finalement que succ(x) soit dans le sous arbre droit de x. En plus, si succ(x)
a un fils gauche, alors encore une fois on a cl(x) < cl(G(succ(x))) < cl(succ(x)) et a nest pas
possible.
(c) On montre dabord que, sil existe, le succ(x) est un anctre de x. Cest claire que succ(x) ne peut
pas apparitre dans un sous arbre de x et succ(x) 6= x. Don on a deux possibilits : succ(x) est
un anctre de x ou succ(x) et x ont un prmier anctre commun u 6= succ(x). Dans le deuxime
cas on aurait que succ(x) est dans le sous arbre droit de u et x est dans le sous arbre gauche de u
(linverse nest pas possible) et donc cl(x) < cl(u) < cl(succ(x)) : a est en contradiction avec
la dfinition de successeur de x.
1
2
3
4

Fonction min(a : arbre) : arbre


dbut
si (estVide(G(a))) alors
retourner a;
retourner min(G(a));

5
6

fin

1
2
3
4

Fonction succ(a : arbre) : arbre


dbut
si (estVide(D(a))) alors
retourner min(D(a));
y := pre(a);
tant que (estVide(y) x = D(y)) faire
x := y;
y := pre(y);

5
6
7
8

retourner y;

9
10

fin

On effectue un simple parcours de larbre partir du nud x soit vers le bas, soit vers le haut,
donc la complexit en temps est O(h). Si on veut calculer la complexit en fonction du nombre n
de cls, dans le meilleur des cas la complexit est O(lg n) et dans le pire des cas O(n).

Solution 4 Deux cas sont possibles :


Cas 1 : x est le fils droit de y. Comme les cls sont distinctes, on en dduit que cl(y) < cl(x).
Considrons un noeud n quelconque diffrent de x et de y.
Sous cas 1 : n est un anctre de y. Ou bien y est dans le sous arbre droit de n, et alors x lest aussi et
on en dduit que cl(n) < cl(y) < cl(x). Ou bien y est dans le sous arbre gauche de n, et alors
x lest aussi et on en dduit que cl(y) < cl(x) < cl(n).
Sous cas 2 : y est un anctre de n. Comme x est une feuille et est le fils droit de y, n est dans le sous
arbre gauche de y et donc cl(n) < cl(y) < cl(x).
Sous cas 3 : n nest pas un anctre de y et y nest pas un anctre de n.
n et y ont un premier anctre commun n0 . Ncessairement, n0 6= y et n0 6= n donc x et n sont dans
les sous-arbres de n0 . Ses deux sous-arbres sont diffrents car n0 est le premier anctre commun :
ou bien y et x sont dans le sous arbre droit de n0 et n est dans le sous arbre gauche de n0 , et alors
cl(n) < cl(y) < cl(x), ou bien y et x sont dans le sous arbre gauche de n0 et n est dans le sous
arbre droit de n0 , et alors cl(y) < cl(x) < cl(n).
Donc pour tout noeud n diffrent de x et de y, on a cl(n) < cl(y) < cl(x) ou cl(y) < cl(x) <
cl(n), on peut donc conclure que cl(x) est la plus petite cl de larbre suprieure cl(y).
Cas 2 : x est le fils gauche de y et en menant un raisonnement semblable, on montre que cl(x) est la
plus grande cl de larbre infrieure cl(y).

Solution 5 Remarquons dabord que la complexit du parcours infixe volue en (n).


Pour la construction de lABR, dans le meilleur des cas, aprs chaque insertion, larbre est quilibr
donc la complexit de linsertion est O(lg k) o k est le nombre de valeurs dj insres. Donc la construction de lABR volue en O(nk=1 lg k).
Or nk=1 lg k = lg(n!) et daprs la formule de Stirling
 n

n
(1 + (n1 ))
n! = 2n
e
donc

1
lg(2n) + n lg n n lg(e) + (n1 )
2
On en dduit que la complexit du tri dans le meilleur des cas volue en O(n lg n).
lg(n!) =

Dans le pire des cas, aprs chaque insertion, larbre est compltement dsquilibr donc la complexit
de linsertion est O(k) o k est le nombre de valeurs insres. Donc la construction de lABR volue en
O(nk=1 k) = O(n2 ). Dans le pire des cas, la complexit du tri volue en O(n2 ).

Solution 6
Rponse 6. 100, 1, 40, 30, 32, 34, 33.
Rponse 7.
1
2
3
4
5
6
7

1
2
3
4
5
6
7

1
2
3
4
5
6

Fonction rotationGauche(a : arbre)


dbut
b := D(a);
D(a) := G(b);
G(b) := a;
retourner b;
fin
Fonction rotationDroite(a : arbre)
dbut
b := G(a);
G(a) := D(b);
D(b) := a;
retourner b;
fin
Procdure insertionRacine(a : arbre, k : entier)
dbut
si (estVide(a)) alors
a := nouvArbre(k, arbreVide(), arbreVide());
// cre un nouveau arbre avec cl k
retourner ;
si (k < cl(a)) alors
G(a) := insertionRacine(G(a), k);
a := rotationDroit(a);

7
8
9

sinon
D(a) := insertionRacine(D(a), k);
a := rotationGauche(a);

10
11
12

retourner ;

13
14

fin

Dans le pire cas on appel rcursivement la fonction insertionRacine h fois, o h est la hauteur de
a. Le fonctions rotationDroite et rotationGauche ont complexit (1) et donc la complexit de
insertionRacine est O(h) (O(lg n)).

Vous aimerez peut-être aussi