Vous êtes sur la page 1sur 22

UNIVERSITÉ D’ÉTAT D’HAÏTI

FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

CHAPITRE 8

LES ARBRES

8 Les arbres
Un arbre est une structure homogène composée d’éléments,
appelés nœuds, qui contiennent de l'information et de liens
(pointeurs) vers des éléments du même type.
D'une manière plus formelle, on peut dire qu'un arbre de
type de base T est :

un nœud de type T (racine) auquel peut être


associé un nombre fini de sous-arbres disjoints
descendants (disjoints: c'est-à-dire n'ayant pas
de nœud en commun).

Une structure d'arbre est souvent illustrée sous la forme suivante :

Fig.8.1. Illustration d'une structure d'arbre

Les structures d'arbres possèdent un double intérêt: d'une part les données qui interviennent
dans de nombreux problèmes sont naturellement structurées en arbres (hiérarchies d'objets,
imbrication d’objets, choix et décisions, arbres syntaxiques, etc.), d'autre part elles
permettent de représenter efficacement des ensembles d'objets ou des applications, on parlera
dans ce cas d'arbres de recherche (search trees).

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 114


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

8.1 Définitions
Un arbre est l’abstraction qui modélise une structure hiérarchique. Un arbre avec racine
est composé de deux ensembles N et A appelés respectivement l'ensemble des nœuds et
l'ensemble des arcs (liens) et d'un nœud particulier r appelé racine de l'arbre. Les éléments
de A sont des paires ( n1 , n2 ) d'éléments de N. Un arc ( n1 , n2) établit une relation entre
n1, appelé nœud parent, et n2, appelé nœud enfant de n1, A doit être tel que chaque nœud,
sauf la racine, a exactement un parent.

Noeuds niveau 0
racine
noeuds

Noeud père
Noeuds niveau 1
arc
Noeuds intérieurs
Hauteur de l’arbre=3 = hauteur racine

Noeud fils
Noeuds niveau 2

Noeuds niveau 3

feuilles

Fig.8.2. Les différentes parties d’une structure d'arbre

On appelle feuille de l'arbre les nœuds qui n'ont pas d'enfant et nœud intérieur les nœuds
qui ne sont ni des feuilles ni la racine.
Le degré d'un nœud est le nombre de ses enfants.
le niveau d'un nœud est le nombre d'arcs qu'il faut remonter pour atteindre la racine depuis
ce nœud (la racine est donc de niveau 0).
La hauteur d’un nœud ni est la longueur du plus long chemin (nombre d’arcs) depuis ni
jusqu’à une feuille.
La hauteur d’un arbre est la hauteur de la racine.
La profondeur d’un arbre est le nombre de nœuds qu’il faut parcourir partant de la racine,
pour atteindre le nœud le plus éloigné. C’est le nombre de nœuds contenu dans le sous-
arbre le plus haut, partant de la racine. La profondeur de la racine est égale à 1, donc on
compte la racine.

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 115


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

La profondeur d’un nœud est le nombre de nœuds qu’il faut parcourir, partant de la racine,
pour atteindre ce nœud.

Degré d’un arbre


On peut fixer un degré maximum pour chaque arbre. On parlera alors d'arbre unaire,
binaire, ternaire, …etc. Le degré d’un arbre correspond au degré le plus élevé de ses
nœuds. Une liste linéaire chaînée est un arbre de degré 1.
Un arbre de degré 2 est appelé arbre binaire. Un arbre de degré supérieur à 2 est appelé
arbre multiple.

Note: Systèmes de numérotation: unaire (1), binaire (0,1), ternaire (0,1,2), quaternaire
(0,1,2,3), quinaire (0,1,2,3,4), sénaire (0,1,2,3,4,5), septénaire (0,1,2,3,4,5,6), octal
(0,1,2,3,4,5,6,7), nonaire (0,1,2,3,4,5,6,7,8), décimal (0,1,2,3,4,5,6,7,8,9).

Un arbre est dit équilibré (ou à critère d'équilibre) si, à chaque niveau, la profondeur des
différents sous-arbres (ou branches) ne varie pas de plus d'un niveau.
Un arbre qui n'est pas équilibré est dit un arbre dégénéré.

Si l'ordre entre les sous-arbres enfants est pris en compte on parlera d'arbre ordonné (à ne
pas confondre avec un arbre trié).

Un arbre ordonné est un arbre où la position respective des sous-arbres reflète une relation
d'ordre. Par exemple, l’ordre des fils de n1 dans la figure suivante est, à partir de la
gauche, n2, puis n3 et enfin n4. Cet ordre de la gauche vers la droite peut être étendu de
manière à ordonner tous les nœuds d’un certain ordre de sorte que si m et n sont des frères
et si m est à la gauche de n, alors tous les descendants de m sont à la gauche de tous les
descendants de n.

n1

n2 n3 n4

n5 n6 n7

Fig.8.3.Une structure d'arbre avec sept noeuds

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 116


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

8.2 Propriétés d’un arbre


Les propriétés d’un arbre sont les suivantes :

a) Il existe un nœud particulier appelé la racine.

b) Tout nœud ni autre que la racine est relié par un arc à un autre nœud nj appelé le
père de ni.

c) Un arbre est qualifié de connexe car si on commence à n’importe quel nœud ni


autre que la racine, puis si on se déplace vers le père de ni, puis vers le père du
père de ni et ainsi de suite, on atteindra certainement la racine de l’arbre.

Si p est le père du nœud n, on dit également que n est un fils de p. Un nœud peut avoir zéro
ou plusieurs fils, mais tout nœud autre que la racine a exactement un père. De plus, la
séquence des pères partant d’un nœud vers la racine est toujours unique.

Rappel: La profondeur d’un arbre est le nombre de nœuds qu’il faut parcourir partant de la
racine, pour atteindre le nœud le plus éloigné.

Le nombre maximum de nœuds qu'un arbre de profondeur "p" et de degré "d" peut
contenir, si tous les nœuds internes ont "d" descendants, est :

Nd(p)= di

car, à la racine, on a 1 nœud,


au niveau 1, on a d nœuds,
au niveau 2, on a d2 nœuds,
au niveau p-1, on a dp-1 nœuds,

en particulier, pour un arbre binaire, on a :

N2(p)= 2i=2p-1

La profondeur d'un arbre binaire équilibré, ayant N nœuds, est toujours comprise entre

log2(N+1) et *log2(N+2) -( -2)

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 117


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

8.3 Les opérations élémentaires sur les arbres


Les opérations les plus courantes que l'on effectue sur une structure d'arbre sont les
suivantes :

 insertion : à gauche ou à droite d'un nœud terminal (cas d'un arbre binaire).
 suppression : d'une feuille, d'un nœud intérieur.
 recherche d'un élément.
 parcours : en ordre, en pré-ordre, en post-ordre (cas d'un arbre binaire).

Il est bien entendu possible d'effectuer bien d'autres opérations sur des arbres (voir section
8.5). Par exemple combiner 2 arbres, extraire un sous-arbre d'un arbre, … etc. Ces
opérations dépendent étroitement du problème qu'elles sont sensées résoudre.

8.3.1 Exemple d’insertion d’éléments dans un arbre (cas d'un arbre de tri)
On suppose que les éléments de l’arbre sont des entiers.

Note:
Un arbre de tri est un arbre binaire dont la structure reflète une relation d'ordre entre les
éléments, basée sur une clé de tri. Principe d'insertion d'un élément dans un arbre de tri
(ordre croissant): on parcourt l'arbre, si la valeur de l'élément courant est supérieure à la
valeur de l'élément à insérer, on l'insère à gauche, sinon, on l'insère à droite.

/* définition d'un nouveau type de données pour implémenter l'arbre */

struct Noeud
{
int info;
struct Noeud *gauche;
struct Noeud *droit;
};

typedef struct Noeud TypNoeud;

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 118


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

/* défi nition de la fonction principalee */

void main(void)
{
TypNoeud * parbre; /* pointeur qui va référencer l’arbre */
TypNoeud * p, q;
int number; /* variable qui va contenir l’élément à insérer */

scanf("%d", &number); /* saisie du premier élément à insérer */


parbre=creer_arbre(number); /* appel de la fonction créer_arbre avec
comme paramètre la valeur à insérer, puis
affectation de l’adresse de l’arbre à parbre */
while(scanf("%d", &number) !=EOF) /* Tant qu’il y a d’éléments à
insérer, faire . EOF=[Ctrl]+Z */
{
p=q=parbre;
while(number !=p->info && q !=NULL)
{
p=q; Recherche du sous-
if(number<p->info) arbre dans lequel on
q=p->gauche; doit insérer le
else nouvel élément.
q=p->droit;
} Si c’est un doublon,
if(number==p->info) on l’insère à droite
{printf("%d est un doublon\n", number);
de l’élément courant
ins_droit(p,number);
}
else
{
if(number <p->info)
ins_gauche(p,number); /* Si c'est inférieur à l'élém-
ent courant, insérer l’élément
à gauche */
else
ins_droit(p,number); /* insérer l’élément à droite
de l’élément courant */
}
}
ParEnOrdre(parbre); /* affichage des éléments de l’arbre en ordre */
} /*La fonction ParEnOrdre est définie à la section 8.4.2*/

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 119


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

/* définition de la fonction créer_arbre, qui crée un arbre */

TypNoeud * creer_arbre(int x) /* x est la première valeur insérée


dans l’arbre */
{
TypNoeud * p; /* p est le pointeur qui va recevoir l’adresse du
nouveau nœud */
p=creer_noeud(); /* création du nouveau nœud */
if(p==NULL)
{printf("\nPlus d espace memoire\n");
exit(0);
}
else
{p->info=x;
p->gauche=NULL;
p->droit=NULL;
}
return(p); /* retour de l’adresse de l’arbre à la fonction appelante */
}

/* définition de la fonction ins_gauche qui permet d’insérer un élément


au champ gauche du nœud courant */

void ins_gauche(TypNoeud * p, int x)


{TypNoeud * q;

if(p==NULL)
printf("Insertion annulee\n"); /* si p pointe vers NULL, l’élément
courant n’existe pas */
else
if(p->gauche !=NULL) /* test pour voir si un élément a déjà été
inséré à gauche de l’élément courant*/
printf("Insertion non valide\n");
else /* le champ gauche de l’élément courant
n’a pas encore d’élément */
{
q=creer_noeud(); /*création du nouveau nœud */
if(q==NULL)
{
printf("\n Insertion échouée. Espace insuffisant.\n") ;
return() ;
}

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 120


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

else
{
q->info=x;
p->gauche=q; /* établissement du lien avec le père */
q->gauche=NULL;
q->droit=NULL;
}
}
}

/* définition de la fonction ins_droit qui permet d’insérer un élément à droite du


champ courant */
void ins_droit(TypNoeud * p, int x)
{
TypNoeud * q, r;

if(p==NULL)
printf("Insertion annulee\n");
else
{
q=creer_noeud(); /* création du nouveau nœud */
if(q==NULL)
{
printf("\n Insertion échouée. Espace insuffisant.\n") ;
return() ;
}
else
{
q->info=x;
r=p->droit;
p->droit=q; /* établissement du lien avec le père */
q->gauche=NULL;
q->droit=r;
}
}
}

/* définition de la fonction de création d’un nœud */


TypNoeud * creer_noeud(void)
{
return((TypNoeud *) malloc(sizeof(struct Noeud));
}

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 121


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

/*Cette fonction peut être aussi implémentée de la façon suivante: */


TypNoeud * creer_noeud(void)
{
TypNoeud * Pn;
Pn = (TypNoeud *) malloc(sizeof(TypNoeud));
return(Pn);
}

8.3.2 Suppression d’un nœud


La suppression d'un nœud pose généralement plus de problèmes que l'insertion. Pour un
arbre de tri, il faut distinguer trois cas :

 suppression d'une feuille.

 suppression d'un nœud n'ayant qu'un seul descendant.

 suppression d'un nœud ayant deux descendants.

La suppression d'une feuille ne pose pas de problème; il suffit de mettre à Null le pointeur
vers l'élément à détruire et de récupérer la place occupée par l'élément détruit.

Fig. 8.4. Suppression d'une feuille

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 122


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

La suppression d'un nœud n'ayant qu'un seul descendant est à peine plus compliquée. Il
suffit de faire pointer l'ancêtre directement vers le descendant.

Fig. 8.5. Suppression d'un nœud à un seul descendant.

La suppression d'un nœud ayant deux descendants est plus délicate. Il faut d'abord trouver
l'élément le plus à droite du sous-arbre gauche (le plus grand élément inférieur à celui que
l'on veut détruire); ce sera une feuille ou un nœud à un seul descendant gauche. On
transfère alors le contenu de la feuille (ou du nœud à un seul descendant gauche) dans le
nœud que l'on voulait détruire et l'on détruit la feuille (ou le nœud à un seul descendant
gauche) à la place.

Le cas où l'élément le plus à droite du sous-arbre gauche est une feuille est illustré à la
figure 8.6, alors que celui où l'élément le plus à droite du sous-arbre gauche est un nœud à
un seul descendant est illustré à la figure 8.7.

Fig. 8.6. Suppression d'un nœud à deux descendants, échange avec une feuille.

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 123


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

Fig. 8.7. Suppression d'un nœud à 2 descendants, échange avec un nœud à un


descendant.

8.3.3 Recherche d’un élément dans un arbre


La recherche d'un élément dans un arbre de tri est très similaire à l'insertion telle que nous
l'avons vue plus haut. Nous verrons donc ici une variante récursive :

/* Cette fonction recherche un élément dans l’arbre. Elle reçoit en paramètre


l’arbre dans lequel il faut rechercher et la valeur a rechercher. */

void recherche(TypNoeud * prech, int val)


{
TypNoeud * temp, pere;
temp=prech; /* l’adresse du sous-arbre dans lequel on effectue
la recherche est conservee dans temp */
if(prech!=NULL)
{
if(prech->info==val)
{
printf("\nvaleur trouvee");
exit(1) ;
}
/* si la valeur recherchee n’est pas referencee par prech, on con-
serve l’adresse du sous-arbre dans pere, puis on effectue la recher-
che dans le sous-arbre gauche et ensuite dans le sous-arbre droit */

pere=temp;
recherche(temp->gauche, val);
recherche(temp->droit, val);
}
}

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 124


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

8.4 Parcours d’un arbre


On parcourt généralement un arbre pour appliquer un traitement à chacun de ses nœuds.
On distingue deux grandes catégories d'ordre de parcours: le parcours en profondeur et le
parcours en largeur.

8.4.1 Parcours en profondeur


Dans le parcours en profondeur, à partir de la racine on descend dans un sous-arbre, qu'on
explore complètement, puis on passe à un autre sous-arbre, et ainsi de suite jusqu'au dernier
sous-arbre de la racine. Le principe de parcours est le suivant:

/* algorithme de la methode de parcours d’un arbre */

méthode parcourirEnProfondeur( Arbre a)


{
parcourir la racine de a
pour chaque enfant e de a
parcourirEnProfondeur(Sous-arbre e)
}

8.4.2 Cas particulier du parcours des arbres binaires


Dans le cas des arbres binaires on distingue trois sortes de parcours en profondeur:
 pré ordre: on parcourt la racine, puis le sous-arbre gauche, puis le sous-arbre
droit
 post ordre: on parcourt le sous-arbre gauche, puis le sous-arbre droit, puis la
racine
 en ordre: on parcourt le sous-arbre gauche, puis la racine, puis le sous-arbre
droit

L'impression d'un arbre de tri se fait à l'aide d'un parcours en ordre puisque la valeur
stockée dans le nœud racine se situe entre les valeurs du sous-arbre gauche et celles du
sous-arbre droit. L'évaluation d'un arbre syntaxique se fait avec un parcours en post-ordre
puisqu'il faut évaluer les deux opérandes avant de pouvoir traiter l'opérateur. A titre
d'exemple, le parcours en ordre d'un arbre binaire peut se faire de la manière suivante :

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 125


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

/* fonction de parcours d’un arbre en ordre*/


void ParEnOrdre(TypNoeud * arbre)
{
if(arbre->gauche != NULL) /* si le sous-arbre gauche existe, on le
parcours */
ParEnOrdre(arbre->gauche);
Traite(arbre); /* on parcours la racine, traitement eventuel */
if(arbre->droit != NULL) /* si le sous-arbre droit existe, on le
parcours */
ParEnOrdre(arbre->droit);
} /* Fin de la fonction ParEnOrdre */

/* la fonction Traite ne fait ici qu’afficher la valeur de la racine du sous-arbre*/


void Traite(TypNoeud * arbre)
{
printf("%d ",arbre->info);
}

8.4.3 Parcours en largeur


Dans le parcours en largeur on commence par parcourir tous les nœuds de niveau 1 (les
enfants de la racine), puis on parcours tous les nœuds de niveau 2 (les petits-enfants),
puis ceux de niveau 3, etc. L'algorithme général est:

méthode parcourirEnLargeur de Arbre a


{
ce_niveau = {a}
tant que ce_niveau est non vide
{
niveau_inferieur = {} //initialisé à vide
pour chaque arbre s de ce_niveau
{
parcourir la racine de s
niveau_inferieur = niveau_inferieur  les enfants de s
}
ce_niveau = niveau_inferieur
}
}

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 126


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

8.5 Les arbres binaires ordonnés


Parmi les différentes structures d'arbres possibles, une des plus intéressantes à utiliser est la
structure d'arbre binaire ordonné (arbre de tri, arbre syntaxique,...).

Note : Un arbre généalogique est un arbre ordonné non binaire.

Exemple

/* definition du type TypNœud d’un arbre binaire ordonnes */


typedef struct Noeud
{ int info; /* le champ qui contiendra la donnee */
struct Noeud * Gauche; /* pointeur vers le sous-arbre gauche */
struct Noeud * Droite; /* pointeur vers le sous-arbre droit */
}TypNoeud;

TypNoeud * Racine=NULL; /* arbre vide, Racine est le pointeur qui


referencie l’arbre */

Description en terme de type abstrait :


 le rôle d'une structure d'arbre binaire ordonné est de stocker des informations en
conservant, en plus, une hiérarchie entre ces informations. Cette hiérarchie reflète
des liens de dépendance entre les données. Il peut y avoir au plus deux types de
liens (descendants) différents (lien gauche et lien droit).

 la déclaration d'un arbre binaire ordonné doit spécifier le type de bases des
éléments qu'il contiendra (structure homogène).

 primitives de manipulation:
1. initialiser un arbre à vide.
2. définir la racine d'un arbre vide.
3. regrouper un élément (racine) et deux sous-arbres (un des sous-arbres peut
être vide)
4. ajouter un élément (éventuellement tout un sous-arbre) à gauche (ou à
droite) d'un élément ne possédant pas de descendant gauche (ou droit,
respectivement).
5. indiquer si l'arbre est vide.

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 127


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

6. indiquer l'absence éventuelle de descendant gauche (ou droit) pour un


élément auquel on a accès.
7. accéder à la racine de l'arbre.
8. accéder à la racine du sous-arbre gauche (ou droit) d'un élément auquel on a
accès.
9. décomposer un arbre en un élément (ancienne racine) et un ou deux sous-
arbres (suivant que la racine avait un ou deux descendants).
10. détruire un (sous-)arbre (l'arbre peut n'être composé que d'un seul élément).
11. remplacer un sous-arbre par un autre sous-arbre.

Les primitives 3, 9, 10 et 11 peuvent être combinées pour supprimer un élément


quelconque d'un arbre.

Exemple (cas d’un arbre de tri)

#include <stdio.h>
#include <stdlib.h>

/* definition de la structure Noeud */


struct Noeud
{
int info;
struct Noeud *gauche;
struct Noeud *droit;
};

/* renomage du type struct Noeud : TypNoeud */


typedef struct Noeud TypNoeud;

/* declaration des prototypes de fonction */


void preordre(TypNoeud * arbre);
void ins_gauche(TypNoeud * p, int x);
TypNoeud * creer_arbre(int x);
void ins_droit(TypNoeud * p, int x);
TypNoeud * creer_noeud(void);

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 128


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

/* definition de la fonction d’affichage en pre-ordre: preordre */


void preordre(TypNoeud * arbre)
{
if(arbre!=NULL)
{
printf("%d\n",arbre->info); /*affichage de la valeur de la racine
du sous-arbre a afficher */
preordre(arbre->gauche); /* affichage des elements du sous-
arbre gauche */
preordre(arbre->droit); /* affichage des elements du sous-
arbre droit */
}
}

/* definition de la fonction principale */


void main(void)
{
TypNoeud * parbre;
TypNoeud * p, q;
int number;

scanf("%d", &number); /* saisie de la premiere valeur a inserer dans l’arbre */


parbre=creer_arbre(number); /* creation de l’arbre */
while(scanf("%d", &number) !=EOF) /* saisie des autres elements de
l’arbre */
{
p=q=parbre;

/* recherche du sous-arbre dans lequel il faut inserer le nouvel element */


while(number !=p->info && q !=NULL)
{
p=q;
if(number<p->info) /* si le nouvel element est inferieur a la
valeur courante, faire pointer q vers le
sous-arbe gauche, dans le cas contraire,
faire pointer q vers le sous-arbre droit */
q=p->gauche;
else
q=p->droit;
}

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 129


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

/* Recherche de la position ou il faut inserer le nouvel element */

if(number==p->info)
{printf("%d est un doublon\n", number);
ins_droit(p,number);
}
else
{
if(number <p->info)
ins_gauche(p,number);
else
ins_droit(p,number);
}
}
preordre(parbre); /* appel de la fonction d’affichage en pre-ordre
des elements de l’arbre */
}/* fin de la fonction principale */

/*definition de la fonction de creation d’un arbre : créer_arbre */

TypNoeud * creer_arbre(int x)
{
TypNoeud * p;
p=creer_noeud();
if(p==NULL)
{
printf("\n Insertion échouée. Espace insuffisant.\n") ;
return(p) ;
}
else
{
p->info=x;
p->gauche=NULL;
p->droit=NULL;
return(p);
}
}/* fin de la definition de la fonction creer_arbre */

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 130


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

/* definition de la fonction d’insertion a gauche d’un element :ins_gauche */


void ins_gauche(TypNoeud * p, int x)
{
TypNoeud * q;

if(p==NULL)
printf("Insertion annulee\n");
else
if(p->gauche !=NULL)
printf("Insertion non valide\n");
else
{
q=creer_noeud();
if(q==NULL)
{
printf("\n Insertion échouée. Espace insuffisant.\n") ;
return() ;
}
else
{
q->info=x;
p->gauche=q;
q->gauche=NULL;
q->droit=NULL;
}
}
}

void ins_droit(TypNoeud * p, int x)


{
TypNoeud * q, r;
if(p==NULL)
printf("Insertion annulee\n");
else
{
q=creer_noeud();
q->info=x;
r=p->droit;
p->droit=q;
q->gauche=NULL;
q->droit=r;
}
}

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 131


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

TypNoeud * creer_noeud(void)
{
return (TypNoeud *) malloc(sizeof(struct Noeud));
}

8.6 Les arbres syntaxiques


Un arbre syntaxique est une structure chargée de refléter la précédence existant entre les
différents opérateurs et symboles d'un langage. Ils sont souvent utilisés pour représenter
des expressions algébriques. Dans ce cas, chaque nœud intérieur contient un opérateur et
les feuilles contiennent les opérandes. La hiérarchie des sous-arbres reflète la précédence
des opérateurs et des parenthèses.

#define OPERATEUR 0
#define OPERAND 1

/*définition de la structure Noeud */

struct Noeud
{
short int utype;

union
{ /*le type union est utilisé pour définir le champ*/
char chinfo; /*info qui peut contenir un caractère (operateur)*/
float numinfo; /* ou un réel (opérande)*/
}info;
struct Noeud *left;
struct Noeud *right;
};

typedef struct Noeud TypNoeud;

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 132


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

/*définition de la fonction evalbintree qui permet d’évaluer une expression


mathématique stockée dans un arbre binaire et retourne un réel*/

float evalbintree(TypNoeud * tree)


{
float opnd1, opnd2;
char symb;

if(tree->utype==OPERAND) /*si le type de l’élément courant est*/


return(tree->info.numinfo); /*une opérande, retourner sa valeur*/
/*à la fonction appelante */

opnd1=evalbintree(tree->left); /*évaluation du sous-arbre gauche et


affectation du résultat a opnd1.
Exécutée si utype n’est pas une
opérande */

opnd2=evalbintree(tree->right); /*évaluation du sous-arbre droit et


affectation du résultat à opnd2.
Exécutée si utype n’est pas une
opérande et après évaluation du
sous-arbre gauche*/

symb=tree->info.chinfo; /*affectation de l’opérateur à la


variable symb*/

return oper(symb, opnd1, opnd2); /* appel de la fonction oper qui


effectue l’opération opnd1 symb
opnd2. Le résultat est retourné à la
fonction appelante*/
}/*fin de la définition de la fonction evalbintree*/

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 133


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

/*définition de la fonction oper qui effectue l’opération op1 symb op2 et retourne le
résultat sous forme de float */
float oper(char symb, float op1, float op2)
{
switch(symb) /*Le chois de l’opération en fonction du symbole*/
{
case '+': return(op1+op2);
case '-': return(op1-op2);
case '*': return(op1*op2);
case '/': return(op1/op2);
// case '$': return( expon(op1,op2));
default : printf("%s", "Operation illegale");
exit(1);
}return(0);
}/* fin de la définition de la fonction oper*/

Exemple d’arbre syntaxique: (a+b)*c-d/e

Fig.8.8. Arbre syntaxique d'une expression arithmétique.

La construction d'un arbre syntaxique se fait souvent en combinant un élément (opérateur)


et deux arbres (opérandes) pour former un nouvel arbre.

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 134


UNIVERSITÉ D’ÉTAT D’HAÏTI
FACULTÉ DES SCIENCES

Cours : Algorithmes & Structures de Données EN1, EM1, AR1 & GC1

8.7 Les arbres de tri


Un arbre de tri est une structure chargée de refléter une relation d'ordre existant entre
différentes informations. Ces informations doivent comporter un champ (clé de tri) sur
lequel on puisse appliquer une fonction permettant de savoir si un élément doit être avant
ou après un autre. La plupart du temps, ce champ sera de type numérique ou alphabétique
sur lequel on pourra utiliser les opérateurs de comparaison: <, > ou ==. Un arbre de tri
reflète un séquencement (linéaire) des éléments qu'il contient. Le même ensemble de
valeurs peut donc être représenté par différentes configurations d'arbres binaires suivant
l'ordre selon lequel les valeurs auront été saisies.

8.8 Exercices
1- Ecrire un programme en c qui permet d’effectuer les opérations élémentaires suivantes
sur un arbre binaire ordonné de réels. Les fonctions à implémenter sont les suivants :
a) initialisation de l’arbre à vide
b) ajout d’un élément
c) suppression d’un élément
d) vérification de l’état de l’arbre (vide, non vide)
e) accès à la racine de l’arbre
f) recherche d’un élément donné dans l’arbre

Guéla JEAN JACQUES, Ing., MS SD_chap8 Page : 135

Vous aimerez peut-être aussi