Académique Documents
Professionnel Documents
Culture Documents
b c d
ri e f g
4
2- Vocabulaire et propriétés
■ Une séquence de nœuds partant d’un nœud 'a' en suivant
les arcs jusqu’au nœud 'p' s’appelle un chemin de a à p.
■ La longueur d’un chemin est le nombre d’arcs qui se
trouvent sur le chemin(ex : entre a et p, la longueur = 4)
■ Il existe un seul et unique chemin pour aller à un nœud
de l’arbre à partir de la racine
a1
a2
a3
a4
5
2- Vocabulaire et propriétés
■ La hauteur d’un nœud est la longueur du plus long
chemin partant de ce nœud et aboutissant à une feuille.
■ Les hauteurs respectives des nœuds : b, c, d sont 2, 0, 3
■ La hauteur de toute feuille est donc 0.
■ La hauteur de l’arbre est la hauteur de sa racine.
■ L’arité d’un nœud est le nombre de ses fils.
6
3 - Usages des arbres
Les arbres sont utiles pour représenter les données
de manière hiérarchique
Exemple 1
un arbre généalogique :
3 - Usages des arbres
● Les arbres sont utiles pour représenter les données de
manière hiérarchique
● Exemple 2 : organigramme d’une entreprise
3 - Usages des arbres
● Les arbres sont utiles pour représenter les données de
manière hiérarchique
● Exemple 3 : Abrorescence du S.E
donnée donnée
14
4- Arbres binaires de recherche: ABR
■ Un ABR possède de plus une propriété fondamentale à
respecter sur les valeurs des nœud fils.
Exemple :
■ Soit x un nœud quelconque d’un ABR. Pour tout nœud
y du sous-arbre gauche de x , la valeur de y est
inférieure à la valeur de x , et pour chaque nœud z du
sous-arbre droit de x , la valeur de z est supérieure à la
valeur de x
x-> valeur = 5
16
Traitements sur les
arbres binaires de
recherche
17
Etapes:
■ Nous allons traiter un ABR d’entiers.
1. Déclarer un nœud de l’ABR
2. Créer la racine d’un ABR
3. Insérer un nœud dans un ABR
4. Rechercher un nœud dans un ABR
5. Afficher les nœuds d’un ABR: les modes de
parcours d’un ABR
6. Supprimer un nœud
7. Supprimer l’arbre
18
1-Déclaration d’un nœud
■ La déclaration d’un nœud de l’arbre
est la suivante:
struct Noeud {
type valeur ; valeur
struct Nœud * gauche ;
struct Nœud * droit ; Nœud gauche Nœud droit
};
typedef struct Nœud Nœud;
19
Exemple de déclaration d’un nœud d’un
ABR d’entiers
■ La déclaration d’un nœud de l’arbre
est la suivante:
int valeur ;
struct Nœud * gauche ; Nœud fils à droite
Nœud fils de gauche
struct Nœud * droite ;
} Nœud;
20
2-Création de la racine d’un ABR
■ La création de la racine d’un ABR d’entiers revient à
donner des valeurs initiales
racine racine
valeur Gauche Droit 5 NULL NULL
22
3-Insertion d’un nœud dans un ABR
23
3-Insertion d’un noeud dans un ABR
■ Cas 1: la valeur du nouveau nœud se trouve déjà dans
l’arbre
4 5
3 8
2 4 9
24
3-Insertion d’un noeud dans un ABR
■ Cas 2: Insérer un nouveau nœud à gauche de l’ABR
1 5
3 8
2 4 9
1
25
3-Insertion d’un nœud dans un ABR
■ Cas 3: Insérer un nouveau nœud à droite de l’ABR
10 5
3 8
2 4 9
10
26
Explications (exemple du cas 3)
temp
racine
10 5
temp
3 8
temp
2 4 9
10
27
Etapes
■ Créer un nouveau nœud et lui allouer la mémoire
■ Rechercher de façon récursive le bon emplacement de la
valeur : comparer les valeurs à ajouter avec la valeur de
temp.
■ Si nouveau -> valeur < temp -> valeur :chercher dans
le sous arbre gauche
■ Si nouveau -> valeur > temp -> valeur :chercher dans
le sous arbre droit
■ Si nouveau -> valeur == temp -> valeur : on affiche le
message "valeur existe déjà"
■ Si la valeur ne figure pas dans l’arbre, on l’ajoute
28
3-Insertion d’un élément dans un ABR
Noeud* ajouter_noeud ( int n ,Noeud*racine ){
Noeud* nouveau = creer_noeud (n ) ; //étape 1
return ajout_recursif ( nouveau , racine, racine) ; //étape2
}
racine temp
1 5
3 8
2 4 9
1 29
Nœud *ajout_recursif(Noeud*nouv, Noeud*racine, Noeud*
temp ){
if ( racine == NULL) return nouv ; // arbre vide
if ( nouv->valeur == temp->valeur ) // valeur existe
printf("\n Valeur déjà existante\n"); return racine;
else if ( nouv->valeur < temp ->valeur ){
if (temp ->gauche==NULL) temp ->gauche = nouv;
else ajout_recursif( nouv , racine , temp->gauche ) ;
} racine temp
1 5
3 8
2 4 9
30
1
else { // nouveau->valeur > temp ->valeur
if ( tmp->droite == NULL)
temp->droite = nouv ;
else
ajout_recursif( nouv , racine , temp->droite) ;
}
return racine ; racine temp
}
10 5
3 8
2 4 9
10
31
4-La recherche d’une valeur dans un
ABR
4- La recherche d’une valeur dans un
ABR
■ Nous pouvons réaliser la recherche dans l’ABR de façon
itérative ou bien récursive
24
4- La recherche d’une valeur dans un
ABR
•A- Fonction itérative de recherche dans un ABR
■ La fonction itérative utilise une boucle tant que pour
parcourir tous le nœuds de l’arbre et comparer la valeur
recherchée avec les valeurs des nœuds à partir de la
racine. La fonction :
■ Retourne l’adresse du nœud qui contient la valeur
■ Continue la recherche de la valeur avec le fils droit ou
gauche en fonction du résultat de la comparaison de
la valeur recherchée avec le nœud traité.
■ Retourne NULL si la valeur ne se trouve pas dans
l’arbre.
24
4- La recherche d’une valeur dans un
ABR
•Exemple 1 : recherche la valeur 3 dans l’arbre
racine
5
racine
3 8
2 4 9
24
4- La recherche d’une valeur dans un
ABR
•Exemple 2 : recherche la valeur 7 dans l’arbre
racine
5
racine
3 8
racine
2 4 9
NULL
24
4- La recherche d’une valeur dans un
■
ABR
A- Fonction de recherche itérative dans un ABR
24
4- La recherche récursive d’une valeur dans un
ABR
•Exemple 1 : recherche la valeur 1 dans l’arbre
racine
5
racine
3 8
racine
2 4 9
24
4- La recherche récursive d’une valeur dans un ABR
5
racine
3 8
racine
2 4 9
NULL
24
B- Fonction de recherche récursive
Nœud * rechercher_noeud_rec ( int n , Noeud* racine ){
if ( racine->valeur == n) return racine ;
else if (n < racine->valeur ){
if ( racine->gauche != NULL)
return rechercher_noeud_rec(n , racine->gauche);
else return NULL;
} else {
if ( racine->droite!= NULL)
return rechercher_noeud_rec (n , racine->droite ) ;
else return NULL;
}
}
5-Affichage des nœuds d’une
arborescence
5-Affichage des nœuds d’un arbre
43
5-Affichage des nœuds d’une arborescence
45
Exemple
void affiche_prefixe (Noeud* racine ){
printf ( ",%d , " , racine->valeur);
if ( racine->gauche !=NULL)
affiche_prefixe ( racine->gauche ) ;
if ( racine->droite != NULL)
affiche_prefixe ( racine->droite) ;
}
racine
3 8
2 4 9 46
■ Parcours infixe:
■ Traitement du sous-arbre gauche , puis le nœud
courant et enfin le sous-arbre droit
3 8
48
2 4 9
Exercice1
■ Afficher les valeurs des nœuds de l’arbre suivant en
utilisant les 3 types de parcours : préfixe, postfixe et
infixe
49
Solution
■ 1. Parcours préfixe (Courant, Gauche, Droite) : r,a,c,h,d, i , j ,l,b,e,k, f .
■ 2. Parcours postfixe (Gauche, Droite, Courant) : h,c, i ,l, j ,d,a,k,e, f ,b, r .
■ 3. Parcours infixe (Gauche, Courant, Droite) : c,h,a, i ,d,l, j , r,k,e,b, f .
50
Exercice2
■ Afficher l’arbre ci-dessous en utilisant un parcours infixe
52
5-Affichage des nœuds d’une arborescence
53
Suppression d’un noeud
Suppression d’un nœud de l’ABR
L’opération dépend du nombre de fils du nœud à supprimer.
Cas 1 : le noeud à supprimer n’a pas de fils, c’est une feuille. Il suffit de
supprimer le noeud de l’arbre et libérer la mémoire occupée par ce
nœud.
Suppression d’un noeud
Suppression d’un nœud de l’ABR
L’opération dépend du nombre de fils du nœud à supprimer.
courant = courant->gauche;
return courant;
}
Suppression d'un arbre :
L'algorithme de suppression de l'arbre est simple : on
supprime les feuilles une par une. On répète l'opération
autant de fois qu'il y a de feuilles.
Cette opération est donc très dépendante du nombre de
nœud.
En fait cet algorithme est un simple parcours d'arbre.
En effet, lorsque nous devrons traiter la racine, nous
appellerons une fonction de suppression de la racine.
Avant de supprimer la racine, il faut supprimer les sous
arbres gauche et droit.
On en déduit donc que l'algorithme de suppression est
un parcours d'arbre postfixe.
61
Noeud* DetruireArbre(Noeud*T)
{ Noeud* SupNoeud;
SupNoeud=(Noeud*) malloc(sizeof(Noeud));
SupNoeud=T;
if(T!=NULL)
{
if(T->gauche!=NULL)
DetruireArbre(T->gauche);
if(T->droite!=NULL)
DetruireArbre(T->droite);
}
T=NULL;
free(SupNoeud);
return T;
} 62
Solution 2
void DetruireArbre(Noeud**T) //(Noeud*T )
{ Noeud* SupNoeud;
Noeud* Ng; Noeud* Nd;
SupNoeud=(Noeud*) malloc(sizeof(Noeud));
Ng=(Noeud*) malloc(sizeof(Noeud));
Nd=(Noeud*) malloc(sizeof(Noeud));
SupNoeud=*T;
if((*T)->gauche!=NULL && (*T)->droite!=NULL) {
Ng=(*T)->gauche;
Nd=(*T)->droite;
DetruireArbre(&Ng);
DetruireArbre(&Nd);
}
*T=NULL;
free(SupNoeud);
} 63
Arbres binaires de recherche équilibrés :
arbres AVL
Solution
• Obliger l’arbre à être relativement symétrique
• Hauteur du s.-a. gauche proche de la hauteur du s.-a.
droit
Principe :
• Pour chaque nœud, les hauteurs du s.-a. gauche et du
s.-a. droit différent au plus de 1
- Modèle proposé par G.M. Adelson-Velsky et E.M.
Landis (d’où son nom)
Notion de facteur d'équilibrage d'un nœud
• Différence entre les hauteurs des sag et sad
• Un arbre est AVL si tous les nœuds ont un facteur de -1,
0 ou 1
Changements