Chapitre 3 les arbres - E

publicité
Chapitre 4
Structure d'arbre
4.1 Dénition
Un arbre est un graphe connexe sans cycle, non orienté et qui commence
par une racine r, la structure d'arbre induit une partition sur l'ensemble des
n÷uds de l'arbre. En d'autres termes, un arbre est un ensemble de n÷uds
(sommets), un n÷ud contient une information, il est relié avec un n÷ud père
et peut avoir de 0n ls, remarquant qu'il y'a un n÷ud qui n'a pas de père on
l'appel la racine de l'arbre.
taille d’arbre= 15
nombre de feuille= 9
hauteur = 4
nombre de noeuds internes=5
racine
47
noeud interne
11
5
14
20
1
14
38
36
51
39
49
Figure 4.1 un exemple d'arbre avec ses caractéristiques
1
feuille
Vocabulaire et propriétés de la structure arbre
Un arbre (tree ) de n sommet a n − 1 arêtes
Il existe qu'un seul arête entre deux n÷uds les reliant.
La taille d'un arbre est le nombre de n÷ud (number of node ) de
l'arbre.
Un n÷ud peut avoir 0 à plusieurs ls, la racine n'a pas de père.
Une feuille (leaves ) est un n÷ud qui n'a pas de successeurs (ls), les
autres n÷uds sont appelés n÷uds internes
La hauteur (height) d'un arbre est la longueur du plus long chemin à
partir de la racine
Un n÷ud n est dit accessible à partir d'un n÷ud n0 s'il existe un chemin
allant de n0 à n dans l'arbre.
Dans le cas général, un arbre est appelé arbre à n-aires (gure ; mais ils
existent autres types peuvent être considérés comme des cas spéciaux, dans
ce cours on s'intéresse par les arbres binaires (Binary trees, gure 4.1).
4.2 Arbre binaire
Un arbre binaire est une structure de données récursive qui peut être
représenter sous forme hiérarchique formé par des n÷uds, le n÷ud initial
étant appelé racine. Une des propriétés des arbres binaires est que chaque
n÷ud possède au plus deux éléments ls au niveau inférieur, habituellement
appelés ls gauche et ls droit. Du point de vue de ces ls, le n÷ud dont ils
sont issus au niveau supérieur est appelé père.
Au niveau le plus élevé il y a donc un n÷ud racine. Au niveau directement
inférieur, il y a au plus deux n÷uds ls. Un n÷ud n'ayant aucun ls est appelé
feuille. Le nombre de niveaux total, autrement dit la distance entre la feuille
la plus éloignée et la racine, est appelé hauteur de l'arbre. Le niveau d'un
n÷ud est appelé profondeur de n÷ud. On peut utiliser les arbres binaires en
tant que arbre binaire de recherche.
4.2.1
Implémentation d'un arbre binaire
L'implémentation la plus simple d'un arbre binaire est illustrée dans le
listing
type a r b r e = ^abr
abr = e n r e g i s t r e m e n t
noeud : e n t i e r ;
2
gauche , d r o i t e : a r b r e
Listing 4.1 Impléméntation d'un arbre binaire
4.2.2
Parcours d'arbre
Le parcours d'arbre est une façon d'ordonner les n÷uds d'un arbre an de
les parcourir. le résultat du parcours d'un arbre est une liste d'éléments qui
n'est pas souvent explicite . On distingue deux types essentiels de parcours :
en profondeur ou en largeur. Dans les parcours en profondeur on distingue
à nouveau le parcours préxe(pré-ordre), le parcours inxe (in-ordre) et le
parcours suxe(post-ordre), dans la suite on utilise l'arbre de la gure 4.2 .
1
2
4
3
5
6
0
7
9
Figure 4.2 Parcours d'arbre binaire
4.2.3
Parcours d'arbre en profondeur
Ce parcours, tient toujours à visiter le n÷ud le plus éloigné de la racine
que possible, à la condition qu'il soit le ls d'un n÷ud déjà visité. À l'opposé
des parcours en profondeur sur les graphes, il n'est pas nécessaire de connaître
les n÷uds déjà visités, car un arbre ne contient pas de cycles. Les parcours
préxe, inxe et postxe sont des cas particuliers de ce type de parcours.
Dans ce parcours, sa version itérative doit conserver une liste des éléments
en attente de traitement. La liste utilisée dans ce parcours doit avoir une
structure de pile (de type LIFO, Last In, First Out ).
3
Parcours préxe
Le parcours préxe ache les valeurs de l'arbre en pré-ordre. C'est à dire
on visite la racine ainsi que le ls gauche puis le ls droit, il faut bien noter
que cette procédure est récursive.
Procédure parcours − pref ix( A : arbre)
Début
ecrire(A ∧ .noeud) parcours − pref ix(A
Si (non(arbre − vide(A ↑ .gauche))) Alors
parcours − pref ix(A ↑ .gauche) ;
.gauche) ;
↑
Fin Si
Si (non(arbre − vide(A ↑ .droite))) Alors
parcours − pref ix(A ↑ .droite) ;
Fin Si
Fin
Algorithme 1 Parcours préxe d'un arbre binaire
1
1
2
2
4
6
3
3
5
4
6
5
8
7
Chaine de parcours préfixe= 1, 2, 3, 5, 6, 7, 4, 0, 9
Figure 4.3 Parcours préxe
4
7
9
0
Parcours inxe
Le parcours inxe (in ordre) explore le sous-arbre gauche, la racine et le
sous-arbre droit
Procédure parcours − inf ix( A : arbre)
Début
Si (non(arbre − vide(A ↑ .gauche))) Alors
parcours − inf ix(A ↑ .gauche) ;
Fin Si
ecrire(A ↑ .noeud)
Si (non(arbre − vide(A ↑ .droite)))
parcours − inf ix(A ↑ .droite) ;
Alors
Fin Si
Fin
Algorithme 2 Parcours inxe d'un arbre binaire
1
2
1
3
6
4
5
2
3
7
5
0
4
6
8
7
Chaine de parcours infixe= 3, 2, 6, 5, 7, 1, 4, 9, 0
Figure 4.4 Parcours inxe
5
9
Parcours postxe
Le parcours en postxe permet de visiter le sous-arbre gauche, le sousarbre droit et puis la racine.
Procédure parcours − postf ix( A : arbre)
Début
Si (non(arbre − vide(A ↑ .gauche))) Alors
parcours − postf ix(A ↑ .gauche) ;
Fin Si
Si (non(arbre − vide(A ↑ .droite))) Alors
parcours − postf ix(A ↑ .droite) ;
Fin Si
Fin
ecrire(A ↑ .noeud)
Algorithme 3 Parcours postxe d'un arbre binaire
1
2
1
3
6
4
5
2
3
7
5
0
4
6
8
7
9
Chaine de parcours infixe= 3, 2, 6, 5, 7, 1, 4, 9, 0
Figure 4.5 Parcours postxe
4.2.4
Parcours d'arbre en largeur
Dans le parcours en largeur on parcourt l'arbre niveau par niveau. Les
n÷uds de niveau 0 sont sont d'abord parcourus puis les n÷uds de niveau 1
6
et ainsi de suite. Dans chaque niveau, les n÷uds sont parcourus de la gauche
vers la droite. Au Contraire du parcours en profondeur, ce parcours essaie
toujours de visiter le n÷ud le plus proche de la racine qui n'a pas déjà été
visité. En suivant ce parcours, on va d'abord visiter la racine, puis les n÷uds
à la profondeur 1, puis 2, etc. D'où le nom parcours en largeur.
La structure de le d'attente (de type FIFO, First in, rst out ), ce qui
induit que l'ordre de sortie n'est pas le même (i.e. on permute gauche et
droite dans le traitement).
P ro c ed u re P a r c o u r s L a r g e u r (A: a r b r e ) {
// i n i t i a l i s a t i o n de l a f i l e
e n f i l e r ( Racine (A) , f )
Tant que ( f <> n i l ) { // l a f i l e n ' e s t pas v i d e
noeud = d e f i l e r ( f )
e c r i r e ( noeud )
S i ( noeud ^ . gauche ) <> n i ) A l o r s
e n f i l e r ( noeud ^ . gauche , f )
S i ( noeud ^ . d r o i t e ) <> n i l ) A l o r s
e n f i l e r ( noeud ^ . d r o i t e , f )
}
}
Listing 4.2 parcours en largeur
7
Procédure W ideSearch( A : arbre)
Dbut
init(F ) f = F ileV ide;
enf iler(A ↑ .noeud, f );
Tant que (not(f ile − vide(f )))
n = def iler(f );
ecrire(n);
Si (A ↑ .gauche 6= nil)) Alors
enf iler(A ↑ .gauche, f )
faire
Fin Si
Si (A ↑ .droite 6= nil)) Alors
enf iler(A ↑ .droite, f )
Fin
Fin Si
Fait
Algorithme 4 Parcours en largeur d'un arbre binaire
4.2.5
Calcul de la hauteur d'un arbre
On peut dénir cette fonction récursivement comme suit :
un arbre vide est de hauteur 0
un arbre non vide a pour hauteur 1 + la hauteur maximale entre le
sous arbre gauche et le sous arbre droit.
A partir de cette dénition l'algorithme 5 illustre le calcul de la hauteur
d'arbre binaire.
8
Fonction Height( A : arbre) : entier
Dbut
Si (arbre − vide(A))
Height ← 0 ;
Alors
Sinon
Height ← 1 + max(Height(A.gauche), Height(A.droite)) ;
Fin Si
Fin
Algorithme 5 Calcul de hauteur d'un arbre
4.2.6
Calcul de taille d'un arbre
Comme la hauteur de l'arbre, le calcul de la taille de l'arbre c'est à dire
le nombre de n÷ud se calcule récursivement selon la dénition suivante :
La taille d'un arbre vide est 0
La taille d'un arbre qui n'est pas vide est égale à 1 + la taille du sous
arbre gauche + taille du sous arbre droit.
L'algorithme 6 montre comment la taille de l'arbre est calculé.
Fonction N BN ode( A : arbre) : entier
Dbut
Si (arbre − vide(A))
N BN ode ← 0 ;
Alors
Sinon
N BN ode ← 1 + N BN ode(A.gauche) + N BN ode(A.droite) ;
Fin Si
Fin
Algorithme 6 Calcul de la taille d'un arbre
4.2.7
Calcul de nombre de feuilles dans un arbre
Pour calculer le nombre de feuilles on prend la dénition récursive :
Un arbre vide ne contient aucune feuille.
9
Le nombre de feuille dans un arbre non vide est déni de la façon
suivante : Dans le cas où le n÷ud est une feuille alors on renvoie 1,
si c'est un n÷ud interne alors le nombre de feuille est la somme du
nombre de feuille de chacun de ses deux ls.
Ainsi l'algorithme 7 calcul le nombre de feuille dans l'arbre avec f euille(A)
vérié si le n÷ud est une feuille.
Fonction nbleaves( A : arbre) : entier
Dbut
Si (arbre − vide(A))
nbleaves ← 0 ;
Alors
Sinon
Si (f euille(A)) Alors
nbleaves ← 1 ;
Sinon
nbleaves ← nbleaves(A.gauche) + nbleaves(A.droite) ;
Fin Si
Fin Si
Fin
Algorithme 7 Calcul de la taille d'un arbre(nombre de n÷ud)
4.2.8
Calcul de nombre de n÷uds internes
Un n÷ud interne est déni par un n÷ud qui n'est pas racine et n'est
pas feuille, l'algorithme 8 traduit la dénition récursive du calcul de n÷uds
internes suivante :
un arbre vide n'a pas de n÷ud interne.
si le n÷ud en cours est une feuille alors renvoyer 0
si le n÷ud a au moins un ls, renvoyer 1 plus la somme des n÷uds
interne des ls.
10
Fonction internalN ode( A : arbre) : entier
Début
Si (arbre − vide(A)) Alors
internalN ode ← 0 ;
Sinon
Si (f euille(A)) Alors
internalN ode ← 0 ;
Sinon
internalN ode ← 1 + internalN ode(A.gauche) +
internalN ode(A.droite) ;
Fin Si
Fin Si
Fin
Algorithme 8 Calcul de nombre de n÷uds internes d'un arbre
4.3 Arbre n-aires
Un arbre de n-aires est une généralisation des arbres binaires, à la diérence de nombres de ls qu'on peut trouver jusqu'à n ls alors que l'arbre
binaire peut avoir au plus deux ls.
4.3.1
Implémentation
L'implémentation d'un arbre à n-aires peut avoir deux situations diérentes, la première quand le nombre de ls est connu la structure de données
devient un n÷ud qui pointe vers un tableau de n ls, la deuxième situation
quand le nombre de ls est inconnu ou on veut optimiser l'espace mémoire,
l'implémentation de cette dernière est que chaque n÷ud pointe vers le premiers ls et vers son frère, comme le montre la gure 4.6
4.4 Arbre binaire de recherche
Un arbre binaire de recherche (ou ABR) est un arbre binaire qui permet
de représenter un ensemble de valeurs disposant d'une relation d'ordre sur
ces valeurs de tel façon que les n÷uds du sous arbre gauche sont inférieurs
11
Arbre de n-aires /n est inconnu
Vue de l’implementation
Figure 4.6 Implémentation d'arbre n-aires
aux n÷uds du sous arbre droit. Les opérations de base sur les arbres binaires
de recherche sont l'insertion, la suppression, et la recherche d'une valeur.
La gure 4.7 illustre un exemple d'un arbre binaire de recherche, pour
avoir une chaine ordonnée on doit acher les éléments de l'arbre par un
parcours inxe, ainsi la localisation de la plus petite valeur ou le minimum ici
c'est 5 dans l'arbre est obtenu par une descente vers les ls à gauche jusqu'au
dernier qui est le minimum, et c'est applicable aussi pour le maximum qui
est situé dans l'extrême droit dans l'exemple de la gure : 51.
33
15
47
10
5
20
38
18
36
51
39
49
Figure 4.7 Exemple d'un ABR
4.4.1
Insertion d'un élément
Pour insérer une valeur on commence par une recherche : on cherche la
valeur du n÷ud à insérer ; lorsqu'on arrive à une feuille, on ajoute le n÷ud
comme ls de la feuille en comparant sa valeur à celle de la feuille : si elle
est inférieure, le nouveau n÷ud sera à gauche ; sinon il sera à droite. Le
code d'insertion illustré dans l'algorithme 9 s'exécute récursivement, avec une
remarque qu'il faut retenir, l'élément inséré est toujours une feuille.
12
Procédure InsertionABR( valeur : entier,var
Début
Si (arbre − vide(A)) Alors
A:
arbre)
cre − arbre(A, nil, nil) ;
Sinon
Si (valeur>A.noeud) Alors
InsertionABR(valeur, A.droite
Sinon
Si (valeur<A.noeud) Alors
InsertionABR(valeur, A.gauche
Fin Si
Fin Si
Fin Si
Fin
Algorithme 9 Insertion dans un ABR
Dans l'exemple de la gure 4.7 on veut insérer la valeur 4 dans l'arbre,
après la recherche de son emplacement le mieux adéquat, puisque 4 est une
valeur inférieur à la racine 33 encerclé en blue on l'insère dans le sous arbre
gauche ainsi de suite jusu'a trouver la feuille où insérer la valeur 4 (voir gure
4.8).
33
47
15
20
10
5
18
38
36
51
49
insertion de 4
4
Figure 4.8 Insertion de la valeur 4 dans l'ABR
13
4.4.2
Recherche d'un élément
Pour rechercher une valeur dans un ABR, il faut parcourir une branche à
partir de la racine, en descendant chaque fois sur le ls gauche ou sur le ls
droit suivant que la valeur du n÷ud encourt est plus grande ou plus petite
que la valeur cherchée. On arrête la recherche si la valeur est trouvée ou
si on atteint une feuille donc l'élément n'existe pas, l'algorithme 10 montre
comment la recherche est faite dans un ABR de façon récursive.
Fonction rechercher( valeur : entier, A : arbre) : booléen
Début
Si (arbre − vide(A)) Alors
recherche ←− f aux ;
Sinon
Si (valeur = A.noeud) Alors
recherche ←− vrai ;
Sinon
Si (valeur>A.noeud) Alors
rechercher(valeur, A.droite)
Sinon
rechercher(valeur, A.gauche)
Fin Si
Fin Si
Fin Si
Fin
Algorithme 10 Recherche d'une valeur dans un ABR
En utilisant l'exemple de la gure 4.7 pour chercher la valeur 39, en
comparant la valeur recherchée par le n÷ud en court à partir de la racine, on
trouve 39 alors que 17 est normalement située à gauche de 18 qui n'est pas
les cas (voir gure 4.11.
4.4.3
Successeur d'un n÷ud
Le successeur d'un n÷ud p dans un arbre A si il existe, est le n÷ud de n
qui a la valeur la plus petite des valeurs qui gurent dans l'arbre A et qui est
plus grand que la valeur de p. Si p possède un ls droit, son successeur est
le n÷ud d'extrême gauche dans le sous-arbre droit. Si p n'a pas de ls droit
14
33
15
47
10
20
5
51
38
18
36
49
39
33
47
15
10
5
38
20
36
18
51
39
49
Figure 4.9 Recherche de la valeur 39 et 17 dans l'ABR
15
alors le successeur de p est le premier de ses ascendants tel que p apparait
dans son sous-arbre gauche. Si cet ascendant n'existe pas c'est que p a la plus
grande valeur dans l'arbre. La gure 4.10, montre le successeur de la valeur
33 qui est le n÷ud de l'extrême gauche du sous arbre droit c'est à dire 36,
alors que le n÷ud 20 qui n'a pas de ls droit doit chercher dans ses ancêtre
que 20 apparait dans son sous arbre( pour 33, 20 est le plus proche).
33
15
47
10
5
38
20
18
36
51
39
49
Figure 4.10 Exemple de successeur de 20 et de 33
4.4.4
Suppression d'un élément
Pour cette opération on peut avoir trois situation selon le nombre de ls :
Supprimer une feuille :
dans ce cas on supprime le ls directement puisqu'il n'a pas de successeur
Supprimer un n÷ud avec un seul ls :
Supprimer un n÷ud avec deux ls :
Soit un n÷ud qu'on veut supprimer appelé N (le n÷ud de valeur 33 rempli en rouge dans la gure ??).
Pour eectuer la suppression de N il faut l'échanger avec son successeur (arrondi en blue) le plus proche (le n÷ud le plus à gauche du
sous-arbre droit, le n÷ud de valeur 36) ou son plus proche prédécesseur
(le n÷ud le plus à droite du sous-arbre gauche, le n÷ud de valeur 30).
Cela permet de garder l'ordre de l'arbre binaire de recherche. Puis on
applique à nouveau la procédure de suppression à N , qui est maintenant
une feuille ou un n÷ud avec un seul ls.
16
33
15
47
10
20
18
38
30
51
39
36
49
36
15
47
10
20
18
38
30
49
39
Figure 4.11 Suppression de la valeur 33, 5 et 51 dans l'ABR
17
4.4.5
Algorithme d'équilibrage d'ABR
4.5 Application des arbres
18
Téléchargement