Vous êtes sur la page 1sur 51

Cours Algorithmique avancée (WI)

cours 3: Les arbres

Dr. Dhouha Maatar Razgallah


2017/2018
Outline

 Arbre
 Arbre binaire
 Arbre binaire de recherche (ABR)

2
Introduction
Les arbres sont des structures de données fondamentales en informatique très utilisés
dans tous les domaines parce qu’ils sont bien adaptés à la représentation naturelle
d’informations homogènes organisées et d’une grande commodité et rapidité de
manipulation.
Leur usage est multiple car ils captent l’idée de hiérarchie:
Découpage d’un livre en chapitres, sections, paragraphes…

3
Introduction
Expression arithmétique:
L’expression A – (B + C * (D –E)) * F se représente facilement par un arbre où
apparait clairement la priorité des opérations:

4
Définition et terminologies
 Un arbre est une structure de données (souvent dynamique) représentant un
ensemble de valeurs organisées hiérarchiquement (non linéaire).
Chaque valeur est stockée dans un nœud.
Les nœuds sont connectées entre eux par des arêtes qui représentent la relation
parents/fils.

5
Définition et terminologies
 Racine: c’est le nœud qui n’a pas de prédécesseur (parents) et possède 0 ou
plusieurs fils. La racine constitue la caractéristique d’un arbre.
Feuille: c’est un nœud qui n’a pas de successeurs (fils). Une feuille est aussi
appelée nœud externe.
Nœud interne: tout nœud qui admet au moins un successeur (fils).

6
Définition et terminologies
 Sous-arbre: est une portion de l’arbre. Dans l’exemple, le nœud G avec ses deux
fils J et K constituent un sous-arbre.
Une branche: c’est une suite de nœuds connectées de père en fils (de la racine à la
feuille: A-B-E; A-C; A-D-F; A-D-G-J; …
Descendants d’un Nœud: sont tous les nœuds du sous-arbre de racine ce nœud.
Dans l’exemple, les descendants de D sont F, G, H, I, J, K et L.
Ascendants d’un nœud: sont tous les nœuds se trouvant sur la branche de la racine
vers ce nœud. Dans l’exemple, les ascendants de J sont G, D et A.

7
Définition et terminologies
 Taille de l’arbre: est le nombre de nœuds qu’il possède.
Taille de l’arbre de l’exemple = 12
Taille d’un arbre vide = 0
Degré d’un nœud: est le nombre de ses fils. Dans l’exemple, le degré de B est 1, le
degré de D est 4.
Degré d’un arbre: est le degré maximum de ses nœuds. Degré de l’arbre de
l’exemple est 4.

8
Définition et terminologies
Le niveau d’un nœud: est la distance qui le sépare de la racine.
Niveau de la racine = 0
Le niveau de chaque nœud est égal au niveau de son père plus 1
Le niveau du nœud contenant G est égal à 2.

9
Définition et terminologies
Définition récursive:
Cas particulier: NIL est un arbre vide contenant 0 nœud.
Cas général: si n est un nœud et si T1, T2, …, Tm sont des arbres. Alors on peut
construire un nouvel arbre en connectant T1, T2, …, Tm sont des fils à n.
Chaque Ti est défini de la même manière récursivement.
T1, T2, …, tm sont alors des sous- arbres de n.

10
Typologie
Arbre m-aire: est un arbre d’ordre m et le degré maximum d’un nœud est égal à m.
B-arbre: un arbre B d’ordre n est un arbre où:
•La racine a au moins deux fils
•Chaque nœud autre que la racine a entre n/2 et n fils
•Tous les nœuds feuilles sont au même niveau
Arbre binaire: est un arbre où le degré maximum d’un nœud est égal à 2.
Arbre binaire de recherche: c’est un arbre binaire où la clé de chaque nœud est
supérieure à celle de ses descendants gauches et inférieure à celle des ses descendants
droite.
…

11
Arbres binaires

12
Définition
 Un arbre binaire est un arbre où chaque nœud est connecté à deux sous-arbres
(un sous-arbre gauche et un sous arbre droit)
C’est un arbre de degré 2, c’est-à-dire que chaque nœud a au plus deux fils.
Le premier fils d’un nœud n est appelé Fils gauche (FG) et le deuxième fils est
appelé Fils droit (FD).

13
Définition
 Un arbre binaire est dit strictement binaire si chaque nœud interne a exactement
2 fils différents de NIL.

 Un arbre binaire complet est un arbre strictement binaire où toutes les feuilles
sont au même niveau.

14
Modèle

L’arbre est implémenté souvent de manière dynamique comme un


ensemble de nœuds chaînés entre eux.
La structure d’un nœud de l’arbre est la suivante:

Types
noeud =enregistrement
val : élément //valeur à stocker
FG: pointeur sur nœud // FilsGauche
FD : pointeur sur noeud // FilsDroite
Fin enregistrement
Arbre= pointeur sur noeud
Variables
A: Arbre
15
Fonctions de base
• Création d’un arbre vide

Cette primitive retourne un arbre vide. Il suffit de déclarer un pointeur sur un


arbre binaire et de l’initialiser à Nil.

Fonction Créer_arbre_vide () : Arbre


Var
A : Arbre
Début
A←Nil
Retourner (A)
Fin

16
Fonctions de base
• Création d’une feuille
Cette primitive permet de créer un nœud externe contenant une valeur et
retourne sa position en mémoire.

Fonction Créer_Feuille (e : élément ) : Arbre


Var
Feuille : Arbre
Début
Allouer (Feuille)
Feuille->Val ← e
Feuille-> FG ← Nil
Feuille-> FD ← Nil
Retourner (Feuille)
17
Fin
Fonctions de base
• Création d’un arbre
Cette primitive permet de créer un arbre à partir d’un sous-arbre droit et d’un
sous-arbre gauche existants et d’un élément qui représente la valeur de la
racine.
Fonction Créer_arbre (e : élément, SAG: arbre, SAD: Arbre ) : Arbre
Var
père : Arbre
Début
Allouer (père)
père->val ← e
père-> FG ← SAG
père-> FD ← SAD
Retourner (père)
Fin 18
Fonctions de base
• Tester la vacuité d’un arbre
Fonction est_arbre_vide (A: arbre) : booleen
Début
Retourner (A =Nil)
Fin
• Tester si un nœud est une feuille
Fonction est_Feuille (A: arbre) : booleen
Début
Si (NON est_arbre_vide (A)) alors
Retourner (est_arbre vide (A-> SAG ) et est_arbre vide (A-> SAD))
Sinon
écrire (« l’arbre est vide »)
Finsi
Fin
19
Fonctions de base
• Accès à la racine
Cette fonction récupère la valeur contenu dans le nœud racine d’un arbre. Pour pouvoir
accéder aux valeur des autres nœuds il faut d’abord les transformer en racine. Par
exemple , soit x un nœud de l’arbre, pour accéder à la valeur de x, il faut se déplacer
dans l’arbre jusqu’à atteindre le sous- arbre qui a pour racine x.

Fonction racine (A: arbre) : élément


Début
Si (NON est_arbre_vide (A)) alors
Retourner (A-> val )
Sinon
écrire (« l’arbre est vide »)
Finsi
Fin

20
Fonctions de base
• Positionnement sur le fils gauche
Cette primitive permet d’obtenir la position en mémoire du fils gauche d’un arbre.
Fonction Fils_Gauche (A: arbre) : arbre
Début
Si (NON est_arbre_vide (A)) alors
Retourner (A-> FG)
Sinon
écrire (« l’arbre est vide »)
Finsi Fin
• Positionnement sur le fils droite
Cette primitive permet d’obtenir la position en mémoire du fils droite d’un arbre.
Fonction Fils_droit (A: arbre) : arbre
Début
Si (NON est_arbre_vide (A)) alors
Retourner (A-> FD)
Sinon
écrire (« l’arbre est vide ») 21
Finsi Fin
Fonctions de base

• Suppression d’un arbre

Cette primitive permet de détruire la totalité de l’arbre ou du sous-arbre dont la position en mémoire
est fournies en paramètre: cette position est celle de la racine.

Procédure DetruireArbre (A: arbre)


Début
Si (NON est_arbre_vide (A)) alors
DetruireArbre (FilsGauche (A))
DetruireArbre (FilsDroite(A))
Liberer (A)
Finsi
Fin
Il est possible de fournir comme paramètre de cette procédure le nœud racine d’un arbre, le nœud
racine d’un sous-arbre ou le nœud représentant une feuille.

22
Applications
• Taille d’un arbre
Le calcul de la taille d’un arbre revient à calculer le nombre de nœuds de cet arbre.
Fonction taille (A: arbre) : entier
Début
si (A = Nil) alors
retourner (0)
sinon
retourner (1+ taille (A-> FG) + taille (A->FD) )
Finsi

Fin
• Nombre de feuilles d’un arbre
Fonction nombre_feuille (A: arbre) : entier
Début
si (A = Nil) alors
retourner (0)
sinon
si (A-> FG = Nil) et (A->FD = Nil) alors
retourner 1
sinon
retourner (nombre_feuille (A-> FG) + nombre_feuille (A-> FD)) 23
Finsi Finsi Fin
Applications
• Recherche d’un élément dans un arbre

Fonction Recherche (A: arbre, x: entier) : booleen


Début
si (A = Nil) alors
retourner (faux)
sinon
si (A-> val = x) alors
retourner (vrai)
sinon
retourner (Recherche (A-> FG, x) ou Recherche (A-> FD, x))
Finsi
Finsi
Fin

24
Parcours
 Le parcours d’un arbre consiste à passer par tous ses nœuds.
Les parcours permettent d’effectuer tout un ensemble de traitement sur les arbres.
On distingue deux types de parcours:
Des parcours en largeur explorent l’arbre niveau par niveau.
Des parcours en profondeur explorent l’arbre branche par branche où on
descend le plus profondément possible dans l’arbre puis une fois qu’une feuille a
été atteinte, on remonte pour explorer les autres branches en commençant par la
branche ‘’la plus basse’’ parmi celles non encore parcourues.
Le parcours en profondeur peut se faire en:
le Préordre (Préfixe): où on affiche la racine avant ses fils (R, FG, FD)
 L’Inordre (Infixe): où on affiche FG puis racine puis FD (FG, R, FD).
 Le Postordre (Postfixe): où on affiche les fils avant la racine (FG, FD,25R).
Parcours en préordre (préfixe)
 Le parcours préordre de l’arbre R (s’il n’est pas vide) consiste à visiter le nœud
racine (R) ensuite parcourir récursivement en préordre les sous arbres T1 (sous arbre
gauche) puis T2 (sous arbre droit) ce qui donne : [R, T1, T2] ou (RGD)

26
Parcours en préordre (préfixe)

Il s’agit de parcourir la racine d’abord, ensuite explorer le sous-arbre gauche, et


finalement explorer le sous-arbre droit.
La procédure (récursive) qui affiche les valeurs en parcours préfixe d’un arbre A est:

Procédure Préfixe(A: arbre)


Début
Si (NON est_arbre_vide (A)) alors
Ecrire (Racine (A))
Préfixe (FilsGauche (A))
Préfixe (FilsDroite(A))
Finsi
Fin
27
Parcours Inordre (Infixe)
 Le parcours inordre de l’arbre R (s’il n’est pas vide) consiste à parcourir
récursivement en inordre les sous arbres T1 (sous arbre gauche) puis visiter le nœud
racine (R) ensuite parcourir récursivement en inordre T2 (sous arbre droit) ce qui
donne : [T1, R, T2] ou (GRD)

28
Parcours Inordre (Infixe)

Il s’agit d’explorer le sous-arbre gauche, visiter la racine et finalement explorer le


sous-arbre droit.
La procédure (récursive) qui affiche les valeurs en parcours infixe d’un arbre A est:

Procédure Infixe(A: arbre)


Début
Si (NON est_arbre_vide (A)) alors
Infixe (FilsGauche (A))
Ecrire (Racine (A))
Infixe (FilsDroite(A))
Finsi
Fin
29
Parcours Postordre (Postfixe)
 Le parcours postordre de l’arbre R (s’il n’est pas vide) consiste à parcourir
récursivement en inordre les sous arbres T1 (sous arbre gauche) ensuite parcourir
récursivement en inordre T2 (sous arbre droit) puis visiter le nœud racine (R) ce qui
donne : [T1, T2, R] ou (GDR)

30
Parcours Postordre (Postfixe)

Il s’agit d’explorer le sous-arbre gauche, explorer le sous-arbre droit et finalement


visiter la racine.
La procédure (récursive) qui affiche les valeurs en parcours postfixe d’un arbre A
est:

Procédure Postfixe(A: arbre)


Début
Si (NON est_arbre_vide (A)) alors
Postfixe (FilsGauche (A))
Postfixe (FilsDroite(A))
Ecrire (Racine (A))
Finsi
Fin 31
Parcours en Largeur (par niveau)
 Dans le parcours par niveau, tous les nœuds d’un même niveau sont traités avant
de descendre au niveau suivant .
 Il explore les nœuds de l’arbre niveau après niveau, l’exploration se fait dans
l’ordre suivant: le noeud racine, les nœuds du niveau 1, les noeuds du niveau 2,
…etc.

32
Parcours en Largeur
 Pour ce type de parcours on ne peut pas appliquer la récursivité, car l’arbre
n’obéit plus à une définition récursive, mais il est considéré comme étant formés
de niveaux, chaque niveau contenant un certain nombre de nœuds.

 Il faut parcourir les nœuds en ordre du haut vers le bas et de la gauche vers la
droite. Pour cela il faut utiliser une autre structure de données, que nous
appellerons F. Il faut sauvegarder les nœuds visités, en faisant en sorte que les
nœuds d’un même niveau soient successifs dans la structure F. C’est-à-dire que
le frère (ou le cousin) d’un nœud doit précéder ses enfants dans F.

 Nous utilisons une liste pour fournir les éléments de l’arbre à la sortie de la
fonction, mais il est aussi possible de les traiter directement sans les stocker.

 Dans la liste nous allons stocker la valeur contenue dans chaque nœud visité.
 Dans la file nous allons stocker les nœuds de l’arbre. 33
Parcours en Largeur
Fonction parcours Largeur (A: arbre) : liste
var L: liste; F: file; B: arbre
Début
B←A
F ← créer_file vide ()
L ← créer_Liste vide ()
Enfiler (F, A)
Tant que (NON Filevide (F) ) faire
B ← Lirefile (F)
Défiler (F)
si (B != Nil) alors
L ← ajouter_fin (L, Racine (B))
Si (B->FG != Nil) alors
Enfiler (F, FilsGauche (B))
Finsi
Si (B->FD != Nil) alors
Enfiler (F, FilsDroit (B))
Finsi
Finsi
Fintq
Retourner (L) 34
Fin
Arbres binaires de recherche

35
Définition
 Un arbre binaire de recherche (ABR) est un arbre binaire ordonné telque pour
tout nœud n:
 Toutes les valeurs du sous arbre gauche de n sont inférieures ou égales à la
valeur de n
 Toutes les valeurs du sous arbre droit de n sont supérieures ou égales à la
valeur de n

Remarque: Généralement, les valeurs dans un ABR sont uniques; on n’admet pas
de répétition de valeur pour éviter les confusion . Mais si jamais ceci arrive : par
exemple si un arbre contient deux fois la valeur 4, par convention, la deuxième
36
valeur est stockée dans le sous-arbre droit ayant pour racine 4.
Opération élémentaires sur ABR
A- Recherche d’un élément dans un ABR
La recherche est dichotomique, à chaque étape, un sous arbre est éliminé:

37
Opération élémentaires sur ABR
A- Recherche d’un élément dans un ABR
Cette fonction permet de rechercher un élément x dans un ABR et retourner un booléen. Pour
les ABR, les éléments sont stockés de façon à respecter une relation d’ordre, cela rend la
recherche plus beaucoup plus efficace que pour les arbre binaires quelconques.

Fonction Recherche_rec (A: arbre, x: entier) : booleen


Début
si (A = Nil) alors
retourner (faux)
sinon
si (A-> val = x) alors
retourner (vrai)
sinon
si (A-> val < x)
retourner (Recherche_rec (A-> FD, x))
sinon
retourner( Recherche_rec (A-> FG, x))
Finsi
Finsi
Finsi 38
Fin
Opération élémentaires sur ABR
A- Recherche d’un élément dans un ABR (version itérative)
Dans un ABR, on sait de façon précise s’il faut continuer la recherche à gauche ou à droite
pour chaque nœud exploré, alors il est possible d’écrire une version itérativede recherche
dans un ABR.

Fonction Recherche_iter (A: arbre, x: entier) : booleen


Début
Tant que (A != Nil) et (x != Racine (A)) faire
si (A-> val < x) alors
A ← A-> FD
sinon
A ← A-> FG
Finsi
Fintq
si (A = Nil) alors
retourner (faux)
sinon
retourner (vrai)
Finsi
Fin
39
Opération élémentaires sur ABR
B- Insertion d’un élément dans un ABR
Pour insérer un nouvel élément dans un ABR il faut d’abord repérer sa place dans l’arbre, il
faut donc le comparer aux éléments déjà existants dans l’ABR. Enfin l’insérer comme fils
du dernier nœud visité.

40
Opération élémentaires sur ABR
B- Insertion d’un élément dans un ABR
Pour insérer un nouvel élément e dans un ABR il faut d’abord repérer sa place dans l’arbre, il faut donc le
comparer aux éléments déjà existants dans l’ABR. Enfin l’insérer comme fils du dernier nœud visité.
Procédure Inserer_rec (var A: arbre, e: entier)
Var
P: arbre
Début
si (A = Nil) alors
allouer (A)
A-> val ← e
A-> FG ← Nil
A-> FD ← Nil
sinon
si (A-> val > e) alors
Inserer_rec ( A-> FG, e)
sinon
Inserer_rec ( A-> FD, e)
Finsi
Finsi
Fin 41
Opération élémentaires sur ABR
B- Insertion d’un élément dans un ABR (version itérative)
Procédure Inserer_iter (var A: arbre, e: entier) si (père = Nil) alors
Var A←P
p, père : arbre sinon
Début si (Père -> val > e ) alors
père ← Nil père -> FG ← P
P←A Sinon
Tant que (P != Nil) faire père -> FD ← P
père ← P finsi
si (P-> val > e) alors Finsi
P ← P-> FG Fin
sinon
P ← P-> FD
Finsi
Fintq
allouer (P)
P-> val ← e
P-> FG ← Nil
P-> FD ← Nil 42
Opération élémentaires sur ABR
C- Suppression d’un élément d’un ABR
 La suppression dans un ABR est assez compliqué, c’est pour cela que nous allons
détailler tous les cas possibles.

 Pour supprimer un nœud dans un ABR, plusieurs cas de figure peuvent se présenter. Il est
toutefois nécessaire d’obtenir un ABR à l’issue de la suppression.

 D’abord il faut chercher l’élément à supprimer, une fois trouvé on se trouve dans l’une
des situations suivantes, soit « i » le nœud à supprimer:
 1er cas : i est une feuille : on la supprime et on la remplace par Nil.
 2eme cas : i est un nœud qui a un seul fils : on supprime i et on le remplace par
ce fils.
 3eme cas : i est un nœud qui a deux fils : on supprime i et on le remplace par
l’élément minimum se trouvant dans son sous arbre droit (le nœud le plus à
gauche du sous arbre droit)ou par l’élément maximum se trouvant dans son
sous arbre gauche (le nœud le plus à droite du sous arbre gauche).
43
Opération élémentaires sur ABR
C- Suppression d’un élément d’un ABR

44
Opération élémentaires sur ABR
C- Suppression d’un élément d’un ABR

45
Opération élémentaires sur ABR
C- Suppression d’un élément d’un ABR

46
Opération élémentaires sur ABR
C- Suppression d’un élément d’un ABR

47
Opération élémentaires sur ABR
C- Suppression d’un élément d’un ABR

48
Opération élémentaires sur ABR
C- Suppression d’un élément d’un ABR

49
Opération élémentaires sur ABR
C- Suppression d’un élément d’un ABR
Pour le 3ème cas nous avons besoin d’abord de déterminer le plus proche prédécesseur (maximum du SAG du nœud i)
et le plus proche successeur (minimum du SAD du nœud i).
• Fonction maximum ( A: arbre): arbre
Début
si (A-> FD != Nil) alors
retourner (maximum (A-> FD ))
sinon
retourner (A)
Finsi
Fin
• Fonction minimum ( A: arbre): arbre
Début
si (A-> FG != Nil) alors
retourner (minimum (A-> FG ))
sinon
retourner (A)
Finsi
Fin
50
NB: pour la fonction maximum A, sera remplacé par FG(i) et pour minimum, A sera remplacé par FD(i).
Opération élémentaires sur ABR
C- Suppression d’un élément d’un ABR (algorithme global)
• Procédure supprimer_rec (var A: arbre, x: entier) sinon
Var p,Q : arbre si ((A-> FG != Nil) et (A-> FD != Nil)) alors
Début P← minimum (A-> FD) // ou P← maximum (A-> FG)
Si (A=Nil) alors A ->val ← P ->val
écrire(x, ’’ est introuvable’’) supprimer_rec (P, P->val)
Sinon Finsi // 3 eme cas
si(A-> val =x) alors // on distingue 3 cas finsi
si (feuille (A)) alors finsi
libérer (A) // 1er cas Sinon
sinon si(A-> val <x) alors
si ((A-> FG != Nil) et (A-> FD = Nil)) alors supprimer_rec (A-> FD, x)
Q← A sinon
A ← A-> FG supprimer_rec (A-> FG, x)
libérer (Q) finsi
sinon finsi
si ((A-> FG = Nil) et (A-> FD != Nil)) alors Finsi Fin
Q←A
A ← A-> FD 51
libérer (Q) // 2 eme cas

Vous aimerez peut-être aussi