CH 04 - Les Arbres
CH 04 - Les Arbres
CH 04 - Les Arbres
1. Introduction
La structure d'arbre est très utilisée en informatique. Sur le fond on peut considérer un arbre
comme une généralisation d'une liste car les listes peuvent être représentées par des arbres. La
complexité des algorithmes d'insertion de suppression ou de recherche est généralement plus faible
que dans le cas des listes (cas particulier des arbres équilibrés). Les mathématiciens voient les arbres
eux-même comme des cas particuliers de graphes non orientés connexes et acycliques, donc
contenant des sommets et des arcs :
Ci-dessus 3 représentations graphiques de la même structure d'arbre, dans la figure fig-1 tous
les sommets ont une disposition équivalente, dans la figure fig-2 et dans la figure fig-3 le sommet
"rouge" se distingue des autres. Lorsqu'un sommet est distingué par rapport aux autres, on le
dénomme racine et la même structure d'arbre s'appelle une arborescence, par abus de langage dans
tout le reste du document nous utiliserons le vocable arbre pour une arborescence.
Enfin certains arbres particuliers nommés arbres binaires sont les plus utilisés en informatique
et les plus simples à étudier. En outre il est toujours possible de "binariser" un arbre non binaire, ce
qui nous permettra dans ce chapitre de n'étudier que les structures d'arbres binaires.
2. Définitions
2.1. Etiquette
Un arbre dont tous les nœuds sont nommés est dit étiqueté. L'étiquette (ou nom du sommet)
représente la "valeur" du nœud ou bien l'information associée au nœud. Ci-dessous un arbre étiqueté
dans les entiers entre 1 et 10 :
1
Chapitre 4 Les arbres
Pour atteindre le nœud étiqueté 9 , il faut parcourir le lien 1--5, puis 5--8, puis enfin 8--9 soient
4 nœuds donc 9 est de profondeur ou de hauteur égale à 4, soit h(9) = 4.
Pour atteindre le nœud étiqueté 7 , il faut parcourir le lien 1--4, et enfin 4--7, donc 7 est de
profondeur ou de hauteur égale à 3, soit h(7) = 3.
(Certains auteurs adoptent une autre convention pour calculer la hauteur d'un nœud : la racine a pour
hauteur 0 et donc n'est pas comptée dans le nombre de nœuds, ce qui donne une hauteur inférieure
d'une unité à cette définition).
2
Chapitre 4 Les arbres
Remarquons que la hauteur h d'un nœud X est égale au nombre de nœuds dans le chemin :
h( X ) = NbrNœud( Chemin( X ) ).
Nous pouvons définir récursivement la hauteur h d'un nœud X à partir de celle de son parent :
h (racine) = 1;
h ( X ) = 1+ h ( parent ( X ) )
3
Chapitre 4 Les arbres
Remarquons que lorsqu'un arbre a tous ses nœuds de degré 1, on le nomme arbre dégénéré et
que c'est en fait une liste.
2.7. Hauteur ou profondeur d'un arbre
Par définition c'est le nombre de nœuds du chemin le plus long dans l'arbre. La hauteur h d'un
arbre correspond donc au nombre de niveau maximum :
Le degré d'un arbre est égal au plus grand des degrés de ses nœuds :
d°(1) = 4 d°(2) = 0
d°(3) = 0 d°(4) = 2
d°(5) = 1 d°(6) = 0
d°(7) = 0 d°(8) = 2
d°(9) = 0 d°(10) = 0
4
Chapitre 4 Les arbres
3. Arbres binaires
3.1. Définition
Un arbre binaire est un arbre de degré 2 (dont les nœuds sont de degré 2 au plus).
Vocabulaire :
Les descendants (enfants) d'un nœud sont lus de gauche à droite et sont appelés respectivement fils
gauche (descendant gauche) et fils droit (descendant droit) de ce nœud.
Les arbres binaires sont utilisés dans de très nombreuses activités informatiques et comme nous
l'avons déjà signalé il est toujours possible de représenter un arbre général (de degré >2 ) par un arbre
binaire en opérant une "binarisation".
Nous allons donc étudier dans la suite, le comportement de cette structure de données
récursive. L'opérateur filsG( ) renvoie le sous-arbre gauche de l'arbre binaire, l'opérateur filsD( )
renvoie le sous-arbre droit de l'arbre binaire, l'opérateur Info( ) permet de stocker des informations
de type T0 dans chaque nœud de l'arbre binaire.
Nous noterons < rac, fg , fd > avec conventions implicites un arbre binaire dessiné ci-dessous :
5
Chapitre 4 Les arbres
A =
Le nœud reste une structure statique contenant 3 éléments dont 2 sont dynamiques : l'information du
nœud, une référence vers le fils gauche et une référence vers le fils droit.
Exemple
Selon l'implantation choisie, par hypothèse de départ, la référence vers la racine pointe vers la
structure statique (le nœud) < a, ref vers b, ref vers c >
6
Chapitre 4 Les arbres
type
ArbrBin = ^Nœud ;
Nœud = record
info : T0;
filsG , filsD : ArbrBin ;
end;
Var
Tree : ArbrBin ;
Explications :
Objectif : les arbres sont des structures de données. Les informations sont contenues dans les
nœuds de l'arbre, afin de construire des algorithmes effectuant des opérations sur ces informations
(ajout, suppression, modification,...) il nous faut pouvoir examiner tous les nœuds d'un arbre. Nous
devons avoir à notre disposition un moyen de parcourir ou traverser chaque nœud de l'arbre et
d'appliquer un traitement à la donnée rattachée à chaque nœud.
Parcours :
L'opération qui consiste à retrouver systématiquement tous les nœuds d'un arbre et d'y appliquer un même
traitement se dénomme parcours de l'arbre.
Un algorithme classique consiste à explorer chaque nœud d'un niveau donné de gauche à droite, puis de
passer au niveau suivant. On dénomme cette stratégie le parcours en largeur de l'arbre.
7
Chapitre 4 Les arbres
Cet algorithme nécessite l'utilisation d'un file du type Fifo dans laquelle l'on stocke les nœuds.
Largeur ( Arbre )
si Arbre ≠ alors
ajouter racine de l'Arbre dans Fifo;
tantque Fifo ≠ faire
prendre premier de Fifo;
traiter premier de Fifo;
ajouter filsG de premier de Fifo dans Fifo;
ajouter filsD de premier de Fifo dans Fifo;
ftant
Fsi
Un autre algorithme général de parcours d'un arbre est employé très souvent, il s'agit du parcours dit
"en profondeur".
Parcours en profondeur :
La stratégie consiste à descendre le plus profondément soit jusqu'aux feuilles d'un nœud de l'arbre, puis
lorsque toutes les feuilles du nœud ont été visitées, l'algorithme "remonte" au nœud plus haut dont les feuilles
n'ont pas encore été visitées.
Notons que ce parcours peut s'effectuer systématiquement en commençant par le fils gauche, puis
en examinant le fils droit ou bien l'inverse.
Parcours en profondeur par la gauche :
Traditionnellement c'est l'exploration fils gauche, puis ensuite fils droit qui est retenue on dit alors que l'on
traverse l'arbre en "profondeur par la gauche".
Chaque nœud a bien été examiné selon les principes du parcours en profondeur :
8
Chapitre 4 Les arbres
En fait pour ne pas surcharger les schémas arborescents, nous omettons de dessiner à la fin de chaque
nœud de type feuille les deux nœuds enfants vides qui permettent de reconnaître que le parent est
une feuille :
Lorsque la compréhension nécessitera leur dessin nous conseillons au lecteur de faire figurer
explicitement dans son schéma arborescent les nœuds vides au bout de chaque feuille.
parcourir ( Arbre )
si Arbre ≠ alors
Traiter-1 (info(Arbre.Racine)) ;
parcourir ( Arbre.filsG ) ;
Traiter-2 (info(Arbre.Racine)) ;
parcourir ( Arbre.filsD ) ;
Traiter-3 (info(Arbre.Racine)) ;
Fsi
Les différents traitements Traiter-1 ,Traiter-2 et Traiter-3 consistent à traiter l'information située dans
le nœud actuellement traversé soit lorsque l'on descend vers le fils gauche ( Traiter-1 ), soit en allant
examiner le fils droit ( Traiter-2 ), soit lors de la remonté après examen des 2 fils ( Traiter-3 ).
En fait on n'utilise que trois variantes de cet algorithme, celles qui constituent des parcours ordonnés
de l'arbre en fonction de l'application du traitement de l'information située aux nœuds. Chacun de ces
3 parcours définissent un ordre implicite (préfixé, infixé, postfixé) sur l'affichage et le traitement des
données contenues dans l'arbre.
parcourir ( Arbre )
si Arbre ≠ alors
Traiter-1 (info(Arbre.Racine)) ;
parcourir ( Arbre.filsG ) ;
parcourir ( Arbre.filsD ) ;
Fsi
9
Chapitre 4 Les arbres
parcourir ( Arbre )
si Arbre ≠ alors
parcourir ( Arbre.filsG ) ;
parcourir ( Arbre.filsD ) ;
Traiter-3 (info(Arbre.Racine)) ;
Fsi
parcourir ( Arbre )
si Arbre ≠ alors
parcourir ( Arbre.filsG) ;
Traiter-2 (info(Arbre.Racine)) ;
parcourir ( Arbre.filsD ) ;
Fsi
Le lecteur trouvera ailleurs des exemples de parcours selon l'un des 3 ordres infixé, préfixé, postfixé,
nous proposons un exemple didactique de parcours général avec les 3 traitements.
Nous pouvons établir un modèle d'arbre (binaire ici) où les informations au nœud sont au nombre de
3 (nous les nommerons attribut n°1, attribut n°2 et attribut n°3). Chaque attribut est une chaîne de
caractères, vide s'il y a lieu.
10
Chapitre 4 Les arbres
11
Chapitre 4 Les arbres
parcourir ( Arbre )
si Arbre ¹ Æ alors
Traiter-1 (Attribut n°1) ;
parcourir ( Arbre.filsG ) ;
Traiter-2 (Attribut n°2) ;
parcourir ( Arbre.filsD ) ;
Traiter-3 (Attribut n°3) ;
Fsi
Rappellons que le symbole représente la chaîne vide il est uniquement mis dans le texe dans
le but de permettre le suivi du parcours de l'arbre.
Pour bien comprendre le parcours aux feuilles de l'arbre précédent, nous avons fait figurer ci-
dessous sur un exemple, les nœuds vides de chaque feuille et le parcours complet associé :
12
Chapitre 4 Les arbres
Le parcours partiel ci-haut produit le texte algorithmique suivant (le symbole est encore écrit pour
la compréhension de la traversée) :
si B=0 alors
si C=0 alors
ecrire(R est sol)
sinon
ecrire(pas de sol)
Fsi
sinon
Exercice
Soit l'arbre suivant possédant 2 attributs par nœuds (un symbole de type caractère)
L'attribut de gauche est écrit en descendant, l'attribut de droite est écrit en remontant, il n'y a pas
d'attribut ni de traitement lors de l'examen du fils droit en venant du fils gauche.
Terminons cette revue des descriptions algorithmiques des différents parcours classiques d'arbre
binaire avec le parcours en largeur (Cet algorithme nécessite l'utilisation d'un file du type Fifo dans
laquelle l'on stocke les nœuds).
13
Chapitre 4 Les arbres
Largeur ( Arbre )
si Arbre ≠ alors
ajouter racine de l'Arbre dans Fifo;
tantque Fifo ≠ faire
prendre premier de Fifo;
traiter premier de Fifo;
ajouter filsG de premier de Fifo dans Fifo;
ajouter filsD de premier de Fifo dans Fifo;
ftant
Fsi
Les clefs de tous les nœuds du sous-arbre gauche d'un nœud X, sont inférieures ou égales à la clef de
X.
Les clefs de tous les nœuds du sous-arbre droit d'un nœud X, sont supérieures à la clef de X
Nous en avons :
14
Chapitre 4 Les arbres
Prenons par exemple le nœud (25) son sous-arbre droit est bien composé de nœuds dont les clefs sont
supérieures à 25 : (29,26,28). Le sous-arbre gauche du nœud (25) est bien composé de nœuds dont les
clefs sont inférieures à 25 : (18,9).
On appelle arbre binaire dégénéré un arbre binaire dont le degré = 1, ci-dessous 2 arbres binaires de
recherche dégénérés :
Nous remarquons dans les deux cas que nous avons affaire à une liste chaînée donc le nombre
d'opérations pour la suppression ou la recherche est au pire de l'ordre de O(n). Il faudra utiliser une
catégorie spéciale d'arbres binaires qui restent équilibrés (leurs feuilles sont sur 2 niveaux au plus)
pour assurer une recherche au pire en O(log(n)).
Arbre parfait :
c'est un arbre binaire dont tous les nœuds de chaque niveau sont présents sauf éventuellement au dernier
niveau où il peut manquer des nœuds (nœuds terminaux = feuilles), dans ce cas l'arbre parfait est un arbre
binaire incomplet et les feuilles du dernier niveau doivent être regroupées à partir de la gauche de l'arbre.
(parfait complet : le dernier niveau est complet car il contient tous les enfants )
15
Chapitre 4 Les arbres
(parfait incomplet : le dernier niveau est incomplet car il manque 3 enfants, mais ils
sont manquant à la droite du niveau, les feuilles sont regroupées à gauche)
(non parfait : le dernier niveau est incomplet car il manque 1 enfant, les feuilles ne sont pas
regroupées à gauche)
Un autre arbre non parfait :
(non parfait : les feuilles sont bien regroupées à gauche, mais il manque 1 enfant à l'avant dernier
niveau)
16
Chapitre 4 Les arbres
Exemple de rangement d'un tel arbre dans un tableau (pour une vision pédagogique on a figuré l'indice
de numérotation hiérarchique de chaque nœud dans le rectangle associé au nœud) :
Cet arbre sera stocké dans un tableau en disposant séquentiellement et de façon contigüe les nœuds
selon la numérotation hiérarchique (l'index de la cellule = le numéro hiérarchique du nœud).
Dans cette disposition le passage d'un nœud de numéro k (indice dans le tableau) vers son fils gauche
s'effectue par calcul d'indice, le fils gauche se trouvera dans la cellule d'index 2*k du tableau, son fils
droit se trouvant dans la cellule d'index 2*k + 1 du tableau. Ci-dessous l'arbre précédent est stocké
dans un tableau : le nœud d'indice hiérarchique 1 (la racine) dans la cellule d'index 1, le nœud d'indice
hiérarchique 2 dans la cellule d'index 2, etc...
17
Chapitre 4 Les arbres
Le nombre qui figure dans la cellule (nombre qui vaut l'index de la cellule = le numéro hiérarchique du
nœud) n'est mis là qu'à titre pédagogique afin de bien comprendre le mécanisme.
On voit par exemple, que par calcul on a bien le fils gauche du nœud d'indice 2 est dans la cellule
d'index 2*2 = 4 et son fils droit se trouve dans la cellule d'index 2*2+1 = 5 ...
C'est un arbre étiqueté dont les valeurs des nœuds appartiennent à un ensemble muni d'une relation d'ordre
total (les nombres entiers, réels etc... en sont des exemples) tel que pour un nœud donné tous ses fils ont une
valeur supérieure ou égale à celle de leur père.
18
Chapitre 4 Les arbres
Nous remarquons que la racine d'un tel arbre est toujours l'élément de l'ensemble possédant
la valeur minimum (le plus petit élément de l'ensemble), car la valeur de ce nœud par construction
est inférieure à celle de ses fils et par transitivité de la relation d'ordre à celles de ses descendants c'est
le minimum. Si donc nous arrivons à ranger une liste d'éléments dans un tel arbre le minimum de cette
liste est atteignable immédiatement comme racine de l'arbre.
Voici réellement ce qui est stocké dans le tableau :(entre parenthèses l'index de la cellule contenant le
nœud)
Le tas :
L'intérêt d'utiliser un arbre parfait complet ou incomplet réside dans le fait que le tableau est
toujours compacté, les cellules vides s'il y en a se situent à la fin du tableau.
Le fait d'être partiellement ordonné sur les valeurs permet d'avoir immédiatement un extremum à la racine.
19