Vous êtes sur la page 1sur 146

Structures de donnes

listes, piles, files, arbres binaires

Jacques Le Maitre
Universit du Sud Toulon-Var

Ce cours est mis disposition selon les termes


de la licence Creative Commons
Paternit-Pas d'Utilisation Commerciale-Pas de Modification 2.0 France
Bibliographie
Robert Sedgewick, Algorithmes en langage C, InterEditions.
Ouvrage collectif (coordination Luc Albert), Cours et
exercices d'informatique, Vuibert.
Donald E. Knuth, The Art of Computer Programming,
Volume 1, 2 et 3, Addison-Wesley.

Jacques Le Maitre I41 : Types de donnes 2


Dfinition et implantation dun type de donnes
1. Dfinir formellement les donnes de ce type.
2. Dfinir linterface du type de donnes :
un jeu doprations pour manipuler ces donnes en commenant
par les oprations primitives : celles partir desquelles les
autres peuvent tre dfinies.
3. Choisir une reprsentation de ces donnes.
4. Dfinir les oprations relativement cette reprsentation.
5. Choisir un langage de programmation.
6. Dfinir, en termes de ce langage, la reprsentation des
donnes et les oprations.
7. Regrouper ces dfinitions dans un module constituant
limplantation du type de donnes.
Jacques Le Maitre I41 : Types de donnes 3
Structures de donnes tudies
Les listes linaires et deux spcialisations importantes de
ces listes :
les piles
les files
Les arbres binaires.

Jacques Le Maitre I41 : Types de donnes 4


Implantation des structures de donnes
Deux modes dimplantation seront tudis :
structures modifiables en place , pour les listes linaires,
structures non modifiables voluant par reconstruction, pour les
arbres binaires.
Le premier mode implique une programmation par effets
de bord c.--d. o les changements dtat de la mmoire
sont explicites.
Le second mode est parfaitement adapt la
programmation fonctionnelle.
Le premier mode est plus efficace en temps et en mmoire.
Le second mode privilgie une programmation dclarative.
Le langage de programmation choisi est le langage C.
Jacques Le Maitre I41 : Types de donnes 5
LISTES LINAIRES
Dfinition formelle
Soit T un type de donnes.
Une liste linaire de valeurs de type T est une suite
de n (n 0) valeurs v1, ..., vn ranges de faon ce que :
si n > 0, v1 est la premire valeur dans ce rangement et vn est la
dernire,
si 1 < k <n, vk est prcde par la valeur vk-1 et suivie par la valeur
vk+1.
(Donald E. Knuth, The Art of Computer Programming,
Volume 1, Fundamental Algorithms, Third Edition, p. 238)
Notation :
[] liste linaire vide
[v1, ..., vn] liste linaire non vide

Jacques Le Maitre I41 : Types de donnes 7


Oprations primitives sur les listes linaires (1)
On note :
Vide le type dont lunique valeur est la valeur rien note ()
T : un type de donnes,
Liste(T) le type des listes linaires de valeurs de type T,
Position le type des positions dune valeur dans une liste linaire,
Boolen le type dextension {vrai, faux},
positions(l) lensemble des positions des valeurs de la liste linaire
l,
pos(v) la position de la valeur v dans la liste considre,
la modification en place dune liste.

Jacques Le Maitre I41 : Types de donnes 8


Oprations primitives sur les listes linaires (2)
Cration dune liste vide
crer-liste : Vide Liste(T)
crer-liste : () []
Test de liste vide
liste-vide : Liste(T) Boolen
liste-vide : [] vrai
liste-vide : [...v...] faux

Jacques Le Maitre I41 : Types de donnes 9


Oprations primitives sur les listes linaires (3)
Insertion dune valeur en dbut de liste
insrer_au_dbut : Liste(T) T Vide
insrer_au_dbut : ([...], v) ()
effet de bord : [...] [v...]
Insertion dune valeur aprs une position donne
insrer_aprs : Liste(T) Position T Liste(T)
insrer_aprs : (l, p, v) erreur ! (si p positions(l))
insrer_aprs : ([...w...] , p, v) o p = pos(w) ()
effet de bord : [...w...] [...w, v...]

Jacques Le Maitre I41 : Types de donnes 10


Oprations primitives sur les listes linaires (4)
Suppression dune valeur dont la position est donne
supprimer : Liste(T) Position Vide
supprimer : (l, p) erreur ! (si p positions(l))
supprimer : ([...v...], p) o pos(v) = p ()
effet de bord : [...v...] [...]

Jacques Le Maitre I41 : Types de donnes 11


Oprations primitives sur les listes linaires (5)
Slection de la valeur dont la position est donne
valeur : Liste(T) Position T
valeur : (l, p) erreur ! (si p positions(l))
valeur : ([...v...], p) o pos(v) = p v
Remplacement de la valeur dont la position est donne
remplacer : Liste(T) Position T Liste(T)
remplacer : (l, p, w) erreur ! (si p positions(l))
remplacer : ([...v...], p, w) o pos(v) = p ()
effet de bord : [...v...] [...w...]

Jacques Le Maitre I41 : Types de donnes 12


Types paramtrs et polymorphisme
Le type Liste(T) est un type paramtr. Il englobe tous les types
de listes obtenus en remplaant le paramtre de type T par un
type effectif : Liste(Entier), Liste(Flottant), Liste (Point), etc.
Les oprations sur le type Liste(T) sont dites polymorphes car
elles sappliquent toutes les listes quelque soit T.
Par exemple, la fonction :
liste_vide : Liste(T) Boolen
sapplique aussi bien aux listes de types : Liste(Entier),
Liste(Flottant), Liste(Point), etc.
Il nest pas ncessaire dcrire une dfinition pour chacun de ces
types : une seule dfinition, dite gnrique, est suffisante
quelque soit T.
Jacques Le Maitre I41 : Types de donnes 13
Reprsentations dune liste linaire
Plusieurs reprsentations des listes linaires ont t
proposes.
La plupart consistent enregistrer chaque valeur dans une
cellule de la mmoire et chaner ces cellules entre elles.
Elles se diffrencient principalement par :
le mode de mmorisation des cellules : dans un tableau ou bien
dans une zone mmoire alloue dynamiquement,
le mode de de marquage du dbut ou de la fin de la liste,
le mode de chanage des cellules : unidirectionnel ou
bidirectionnel.

Jacques Le Maitre I41 : Types de donnes 14


Notre reprsentation dune liste linaire
Une liste linaire est reprsente comme une chane de
maillons compose :
dun maillon de dbut,
dune suite ventuellement vide de maillons internes,
dun maillon de fin.
Chaque maillon a un identifiant.
Le maillon de dbut contient lidentifiant du 1er maillon interne.
Le ie maillon interne contient la ie valeur de la liste linaire et
lidentifiant du maillon contenant la (i + 1)e valeur.
Le maillon de fin a un identifiant nul.
Le maillon suivant du maillon de dbut dune liste linaire vide
est le maillon de fin.
Une liste est identifie par l'identifiant de son maillon de dbut.
Jacques Le Maitre I41 : Types de donnes 15
Notre reprsentation dune liste linaire

liste non vide

u v w

maillon maillon valeur maillon de fin


de dbut interne

liste vide

Jacques Le Maitre I41 : Types de donnes 16


Proprits de cette reprsentation
La position dune valeur est lidentifiant du maillon qui la contient.
Le chanage est unidirectionnel et dirig de la premire vers la
dernire valeur :
la 1re valeur est atteinte partir du maillon de dbut,
la ke valeur (k > 1) est atteinte partir du maillon contenant la (k 1)e valeur.
Une opration suivant est ncessaire pour passer dun maillon lautre.
Lopration supprimer est remplace par une opration supprimer-
suivant.
Lopration insrer-au-dbut est redondante et donc non dfinie, car :
insrer-au-dbut(l, v) insrer-aprs(l, v)
puisque l est lidentifiant du maillon de dbut.
Une opration fin-liste est ncessaire pour tester que le maillon de fin a
t atteint.

Jacques Le Maitre I41 : Types de donnes 17


crer-liste

crer-liste()

Jacques Le Maitre I41 : Types de donnes 18


fin-liste

fin-liste(m) vrai
m

fin-liste(m) faux
m

Jacques Le Maitre I41 : Types de donnes 19


liste-vide

liste-vide(l) vrai
l

liste-vide(l) faux
l

Jacques Le Maitre I41 : Types de donnes 20


insrer-aprs

insrer-aprs(m, v)

v
m

nouveau
maillon

Jacques Le Maitre I41 : Types de donnes 21


supprimer-suivant

supprimer-suivant(m)

Jacques Le Maitre I41 : Types de donnes 22


suivant

suivant(m1) m2
m1 m2

suivant(m) nul
m

Jacques Le Maitre I41 : Types de donnes 23


valeur

v valeur(m) v
m

Jacques Le Maitre I41 : Types de donnes 24


Reprsentation chane par pointeurs

l v1 v2 v3

mmoire
(_, a1) (v2, a3)
l a2 (v3, a4)
a3
(v1, a2)
a1
(_, 0)
a4
Jacques Le Maitre I41 : Types de donnes 25
Reprsentation d'une liste linaire en C
typedef struct maillon Maillon;
struct maillon typedef Maillon *Liste;
{ struct maillon
valeur NULL {
suivant NULL void *valeur;
} Maillon *suivant;
}
[]

v1 v2 v3

struct maillon struct maillon struct maillon struct maillon


{ { { {
valeur NULL valeur valeur valeur
suivant suivant suivant suivant NULL
} } } }

[v1, v2, v3]

Jacques Le Maitre I41 : Types de donnes 26


Interface du type Liste linaire en C
Les dclarations des types Maillon et Liste ainsi que
les dclarations des fonctions de linterface sont
enregistres dans le fichier TD-liste-lineaire.h.
Les dfinitions des fonctions de linterface sont
enregistres dans le fichier TD-liste-lineaire.c.

Jacques Le Maitre I41 : Types de donnes 27


Polymorphisme
Les fonctions de cet interface sont polymorphes, c.--d.
qu'elles s'appliquent toute liste de valeurs quelque soit le
type T de ces valeurs.
Cela est possible parce que :
ce ne sont pas directement les valeurs qui sont contenues dans les
maillons, mais les adresses des variables contenant ces valeurs,
le champ valeur d'un maillon est de type void *, on peut donc
lui affecter n'importe quel type d'adresse par dfinition du type
void * en C, et donc l'adresse d'une variable de type T.
Pour accder la valeur de la variable dont l'adresse est
contenue dans un maillon, il faudra au pralable convertir
cette adresse en une adresse de variable de type T.
Jacques Le Maitre I41 : Types de donnes 28
Exemple
Supposons que lon veuille crer et manipuler une liste de personnes
dcrites par leur nom et leur ge.
Supposons que la description d'une personne soit une instance du type
Personne dfini par :
typedef struct
{
char *nom,
int age;
} Personne
La description d'une personne insrer dans une liste devra tre
affecte une variable de type Personne (alloue par un appel
malloc, par exemple) :
C'est l'adresse de cette variable qui sera affecte dans le maillon correspondant
la place de cette personne dans cette liste.
Pour obtenir la description de la personne dont l'adresse est contenue
dans un maillon il faudra au pralable convertir cette adresse en une
adresse de type Personne *.
Jacques Le Maitre I41 : Types de donnes 29
Fichier TD-liste-lineaire.h (1)
#ifndef TD_LISTE_LINEAIRE
#define TD_LISTE_LINEAIRE

#include <stdlib.h>
#include <stddef.h>
#include "erreur.h"

typedef struct maillon Maillon;


typedef Maillon *Liste;

struct maillon
{
void *valeur;
Maillon *suivant;
};

Jacques Le Maitre I41 : Types de donnes 30


Fichier TD-liste-lineaire.h (2)
Liste creer_liste(void);
int fin_liste(Maillon *m);
int liste_vide(Liste l);
Maillon *inserer_apres(Maillon *m, void *v); Primitives
void supprimer_suivant(Maillon *m);
Maillon *suivant(Maillon *m);
void *valeur(Maillon *m);

#endif

Jacques Le Maitre I41 : Types de donnes 31


Crer une liste linaire
Liste creer_liste(void)
{
Maillon *d, *f;
d = (Maillon *) malloc(sizeof(Maillon));
if (d == NULL)
erreur("creer_liste");
d->suivant = NULL;
return d;
}

Jacques Le Maitre I41 : Types de donnes 32


Le maillon m est-il le maillon de fin de liste ?
int fin_liste(Maillon *m)
{
return m == NULL;
}

Jacques Le Maitre I41 : Types de donnes 33


La liste l est-elle vide ?
int liste_vide(Liste l)
{
return l->suivant == NULL;
}

Jacques Le Maitre I41 : Types de donnes 34


Insrer un maillon contenant la valeur v
aprs le maillon m
Maillon *inserer_apres(Maillon *m, void *v)
{
Maillon *s;
if (fin_liste(m))
erreur("inserer_apres");
s = (Maillon *) malloc(sizeof(Maillon));
if (s == NULL)
erreur("inserer_apres");
s->valeur = v;
On retourne l'adresse
s->suivant = m->suivant; du maillon insr.
m->suivant = s;
return s;
}

Jacques Le Maitre I41 : Types de donnes 35


Supprimer le maillon suivant le maillon m
void supprimer_suivant(Maillon *m)
{
if (fin_liste(m))
erreur("supprimer_suivant");
if (!fin_liste(m->suivant)) Si le maillon suivant de m
m->suivant = m->suivant->suivant; est la fin de la
} liste, on ne fait rien.

Jacques Le Maitre I41 : Types de donnes 36


Maillon suivant le maillon m
Maillon *suivant(Maillon *m)
{
if (fin_liste(m))
erreur("suivant");
return m->suivant;
}

Jacques Le Maitre I41 : Types de donnes 37


Valeur contenue dans le maillon m
void *valeur(Maillon *m)
{
if (fin_liste(m))
erreur("valeur");
return m->valeur;
}

Jacques Le Maitre I41 : Types de donnes 38


Autres oprations
Longueur dune liste
ne valeur dune liste
Copie dune liste
Fusion de 2 listes dentiers tries par ordre croissant

Jacques Le Maitre I41 : Types de donnes 39


nime maillon de la liste l
Maillon *nieme(Liste l, int n)
{
Maillon *m = l;
int i = 0;
while (!fin_liste(m) && i < n)
Si i est diffrent de n, cest que n
{
est infrieur 0 ou suprieur la
i++;
longueur de la liste : erreur,
m = suivant(m);
cest au programme appelant
}
de vrifier que le rang
if (i != n) demand est valide !
erreur("nieme");
return m;
}

Jacques Le Maitre I41 : Types de donnes 40


Longueur de la liste l
int longueur_liste(Liste l)
{
Maillon *m;
int i = 0;
m = suivant(l);
while (!fin_liste(m))
{
i++;
m = suivant(m);
}
return i;
}

Jacques Le Maitre I41 : Types de donnes 41


Copier la liste l1
Maillon *copier_liste(Liste l1)
{
Liste l2;
Maillon *m1, *m2;
l2 = creer_liste();
m1 = suivant(l1);
m2 = l2;
while (!fin_liste(m1))
{
m2 = inserer_apres(m2, valeur(m1));
m1 = suivant(m1);
}
return l2;
}

Jacques Le Maitre I41 : Types de donnes 42


Fusion de 2 listes dentiers l1 et l2
ordonnes (1)
int entier(void *v)
{ entier point par v
return *((int *) v);
}

Maillon *fusion_listes(Liste l1, Liste l2)


{
Liste l3;
Maillon *m1, *m2, *m3;
l3 = creer_liste();
m1 = suivant(l1);
m2 = suivant(l2);
m3 = l3;
...

Jacques Le Maitre I41 : Types de donnes 43


Fusion de 2 listes dentiers l1 et l2
ordonnes (2)
...
while (!fin_liste(m1) && !fin_liste(m2))
{
if (entier(valeur(m1)) < entier(valeur(m2)))
{
m3 = inserer_apres(m3, valeur(m1));
m1 = suivant(m1);
}
else
{
m3 = inserer_apres(m3, valeur(m2));
m2 = suivant(m2);
}
}
...

Jacques Le Maitre I41 : Types de donnes 44


Fusion de 2 listes dentiers l1 et l2
ordonnes (3)
...
while (!fin_liste(m1))
{
m3 = inserer_apres(m3, valeur(m1));
m1 = suivant(m1);
}
while (!fin_liste(m2))
{
m3 = inserer_apres(m3, valeur(m2));
m2 = suivant(m2);
}
return l3;
}

Jacques Le Maitre I41 : Types de donnes 45


Allocation et libration de maillons (1)
0 (_, adresse case 4)
1 (_, adresse nulle)
l 2 (_, adresse case 3)
3 (v1, adresse case 6)
4 (_, adresse case 9)
l v1 v2 v3 5 (_, adresse case 1)
6 (v2, adresse case 7)
7 (v3, adresse nulle)
libre 8 (_, adresse case 0)
9 (_, adresse case 5)
maillons
Jacques Le Maitre I41 : Types de donnes 46
Allocation et libration de maillons(2)
#include "TD-liste-lineaire.h"

#define TAILLE 1000


static Maillon maillons[TAILLE];
Gestion de la
static int configurer_liste_maillons = 1; mmoire
static Maillon *libre;

static Maillon *allouer_maillon(void)


static void liberer_maillon(Maillon *m) Dans les fonctions
creer_liste,
Liste creer_liste(void) inserer_apres et
int fin_liste(Maillon *m) supprimer_suivant
int liste_vide(Liste l) les fonctions
Maillon *inserer_apres(Maillon *m, void *v) allouer_maillon et
void supprimer_suivant(Maillon *m) liberer_maillon
Maillon *suivant(Maillon *m) seront utilises au lieu
void *valeur(Maillon *m) de malloc et free.

Jacques Le Maitre I41 : Types de donnes 47


Allocation et libration de maillons (3)
static Maillon *allouer_maillon(void)
{
int i;
Maillon *m;
if (configurer_liste_maillons)
{
for (i = 0; i < TAILLE - 1; i++)
maillons[i].suivant = maillons + i + 1;
maillons[i].suivant = NULL;
libre = maillons;
configurer_liste_maillons = 0;
}
if (libre == NULL)
return NULL;
m = libre;
libre = m->suivant;
return m;
}

Jacques Le Maitre I41 : Types de donnes 48


Allocation et libration de maillons(4)
static void liberer_maillon(Maillon *m)
{
m->suivant = libre;
libre = m;
}

Jacques Le Maitre I41 : Types de donnes 49


PILES
Dfinition formelle
Une pile est une liste pile vide pile non vide
linaire l pour laquelle les
insertions et les
suppressions sont v2 sommet
effectues au dbut de l : v1
la premire valeur de l est le
sommet de la pile, [] [v2, v1]
empiler une valeur cest empiler v3 v3 = dpiler
linsrer au dbut de l,
dpiler une valeur, si l est v3
non vide, cest slectionner la
premire valeur de l et la v2 v2 v2
supprimer de l.
v1 v1 v1

Jacques Le Maitre I41 : Types de donnes 51


Oprations primitives sur les piles (1)
On note :
Pile(T) : le type des piles de valeurs de type T
Cration dune pile
crer-pile : Vide Pile(T)
crer-pile : () []
Test de pile vide
pile-vide : Pile(T) Boolen
pile-vide : [] vrai
pile-vide : [v...] faux

Jacques Le Maitre I41 : Types de donnes 52


Oprations primitives sur les piles (2)
Empiler une valeur
empiler : Pile(T) T Vide
empiler : ([...], v) ()
effet de bord : [...] [v...]
Dpiler une valeur
dpiler : Pile(T) T
dpiler : [] erreur !
depiler : [v...] v
effet de bord : [v...] [...]
Slectionner la valeur situe au sommet
sommet : Pile(T) T
sommet : [] erreur !
sommet : [v, ...] v

Jacques Le Maitre I41 : Types de donnes 53


Reprsentation dune pile

v3

v2 v3 v2 v1

v1 sommet

Jacques Le Maitre I41 : Types de donnes 54


crer-pile

crer_pile()

Jacques Le Maitre I41 : Types de donnes 55


pile-vide

pile-vide(p) vrai
p

pile-vide(p) faux
p sommet

Jacques Le Maitre I41 : Types de donnes 56


empiler

p sommet

empiler(p, v)

v
p sommet

Jacques Le Maitre I41 : Types de donnes 57


dpiler
v
p sommet

dpiler(p)

v /
p sommet

Jacques Le Maitre I41 : Types de donnes 58


sommet
v
p sommet

sommet(p)

Jacques Le Maitre I41 : Types de donnes 59


Reprsentation d'une pile en C
struct maillon
{
valeur NULL typedef Liste Pile;
suivant NULL
}

[]

v3 v2 v1

struct maillon struct maillon struct maillon struct maillon


{ { { {
valeur NULL valeur valeur valeur
suivant suivant suivant suivant NULL
} } } }

[v3, v2, v1]

Jacques Le Maitre I41 : Types de donnes 60


Interface
La dclaration du type Pile ainsi que les dclarations des
fonctions de linterface sont enregistrs dans le fichier
TD-pile.h.
Les dfinitions des fonctions de linterface sont
enregistres dans le fichier TD-pile.c.

Jacques Le Maitre I41 : Types de donnes 61


Fichier TD-pile.h
#ifndef TD_PILE
#define TD_PILE

#include "TD-liste-lineaire.h"
#include "erreur.h"

typedef Liste Pile;

Pile creer_pile(void);
int pile_vide(Pile p);
void empiler(Pile p, void *v); Primitives
void *depiler(Pile p);
void *sommet(Pile p);

#endif

Jacques Le Maitre I41 : Types de donnes 62


Crer une pile
Pile creer_pile(void)
{
return creer_liste();
}

Jacques Le Maitre I41 : Types de donnes 63


La pile p est-elle vide ?
int pile_vide(Pile p)
{
return liste_vide(p);
}

Jacques Le Maitre I41 : Types de donnes 64


Empiler une valeur v au sommet dune pile p
void empiler(Pile p, void *v)
{
inserer_apres(p, v);
}

Jacques Le Maitre I41 : Types de donnes 65


Dpiler la valeur au sommet de la pile p
void *depiler(Pile p)
{
void *v;
if (pile_vide(p))
erreur("depiler");
v = valeur(suivant(p));
supprimer_suivant(p);
return v;
}

Jacques Le Maitre I41 : Types de donnes 66


Valeur au sommet de la pile p
void *sommet(Pile p)
{
if (pile_vide(p))
erreur("sommet");
return valeur(suivant(p));
}

Jacques Le Maitre I41 : Types de donnes 67


FILES
Dfinition formelle
Une file est une liste linaire l pour laquelle les insertions sont
ralises la fin de l et les suppressions sont effectues au dbut
de l :
la premire valeur de l est la tte de la file et la dernire est la queue
de la file,
entrer une valeur cest lajouter la fin de de l,
sortir une valeur, si l est non vide, cest slectionner la premire
valeur de l et la supprimer de l.
queue tte
file vide v3 v2 v1 file non vide

[] [v1, v2, v3]

v2 v1 v3 v2 v1 v3 v2
entrer v3 v1 = sortir
Jacques Le Maitre I41 : Types de donnes 69
Oprations primitives sur les files (1)
On note :
File(T) : le type des files de valeurs de type T
Cration dune file vide
crer-file : Vide File(T)
crer-file : () []
Test de file vide
file-vide : File(T) Boolen
file-vide : [] vrai
file-vide : [v...] faux

Jacques Le Maitre I41 : Types de donnes 70


Oprations primitives sur les files (2)
Entrer une valeur dans une file
entrer : File(T) T Vide
entrer : ([...], v) ()
effet de bord : [...] [...v]
Sortir une valeur dune file
sortir : File(T) T
sortir : [] erreur !
sortir : [v...] v
effet de bord : [v...] [...]

Jacques Le Maitre I41 : Types de donnes 71


Oprations primitives sur les files (3)
Slectionner la valeur en tte dune file
tte : File(T) T
tte : [v...] v
tte : [] erreur !
Slectionner la valeur en queue dune file
queue : File(T) T
queue : [...v] v
queue : [] erreur !

Jacques Le Maitre I41 : Types de donnes 72


Reprsentation dune file

file
vide

v3 v2 v1 v1 v2 v3
tte queue

Jacques Le Maitre I41 : Types de donnes 73


crer-file

crer_file()

Jacques Le Maitre I41 : Types de donnes 74


file-vide

file_vide(f) vrai
f

file_vide(f) faux
f

Jacques Le Maitre I41 : Types de donnes 75


entrer

v1 v2
f queue

entrer(f, v3)

v1 v2 v3
f queue

Jacques Le Maitre I41 : Types de donnes 76


sortir
v1 v2 v3
f tte

sortir(f)

v1 / v2 v3
f tte

Jacques Le Maitre I41 : Types de donnes 77


tte
v
f tte

tte(f)

Jacques Le Maitre I41 : Types de donnes 78


queue
v
f queue

queue(f)

Jacques Le Maitre I41 : Types de donnes 79


Reprsentation d'une file en C
typedef struct file *File;
struct file struct maillon struct file
{ { {
liste valeur NULL
Liste liste;
queue NULL suivant NULL Maillon *queue;
} } };

[]

v1 v2

struct file struct maillon struct maillon struct maillon


{ { { {
liste valeur NULL valeur valeur
queue suivant suivant suivant NULL
} } } }

[v1, v2 ]

Jacques Le Maitre I41 : Types de donnes 80


Interface
La dclaration du type File ainsi que les dclarations des
fonctions de linterface sont enregistrs dans le fichier
TD-file.h.
Les dfinitions des fonctions de linterface sont
enregistres dans le fichier TD-file.c.

Jacques Le Maitre I41 : Types de donnes 81


Fichier TD-file.h (1)
#ifndef TD_FILE
#define TD_FILE

#include <stdlib.h>
#include <stddef.h>
#include "TD-liste-lineaire.h"
#include "erreur.h"

typedef struct file *File;

struct file
{
Liste liste;
Maillon *queue;
};

Jacques Le Maitre I41 : Types de donnes 82


Fichier TD-file.h (2)
File creer_file(void);
int file_vide(File f);
void entrer(File f, void *v);
Primitives
void *sortir(File f);
void *tete(File f);
void *queue(File f);

#endif

Jacques Le Maitre I41 : Types de donnes 83


Crer une file
File creer_file(void)
{
File f;
Liste l;
f = (File) malloc(sizeof(struct file));
if (f == NULL)
erreur("creer_file");
l = creer_liste();
f->queue = l;
f->liste = l;
return f;
}

Jacques Le Maitre I41 : Types de donnes 84


La file f est-elle vide ?
int file_vide(File f)
{
return liste_vide(f->liste);
}

Jacques Le Maitre I41 : Types de donnes 85


Entrer une valeur v dans une file f
void entrer(File f, void *v)
{
f->queue = inserer_apres(f->queue, v);
}

Jacques Le Maitre I41 : Types de donnes 86


Sortir une valeur dune file f
void *sortir(File f)
{
void *v;
if (file_vide(f))
erreur("sortir");
v = valeur(suivant(f->liste));
supprimer_suivant(f->liste);
if (file_vide(f))
f->queue = f->liste;
return v;
}

Jacques Le Maitre I41 : Types de donnes 87


Valeur en tte dune file f
void *tete(File f)
{
if (file_vide(f))
erreur("tete");
return valeur(suivant(f->liste));
}

Jacques Le Maitre I41 : Types de donnes 88


Valeur en queue dune file f
void *queue(File f)
{
if (file_vide(f))
erreur("queue");
return valeur(f->queue);
}

Jacques Le Maitre I41 : Types de donnes 89


ARBRES BINAIRES
Dfinition formelle
Un arbre binaire est un v1
AB
ensemble fini de valeurs qui
est : AB
soit vide, AB v2
vide
soit constitu dune racine et
AB AB
des valeurs de deux arbres
binaires disjoints appels v3 v4
sous-arbre gauche et sous-
arbre droit de la racine.
AB AB AB AB
(Donald E. Knuth, The Art of vide vide vide vide
Computer Programming,
Volume 1, Fundamental
Algorithms, 3rd Edition, p.
312) arbre(v1, arbre(), arbre(v2, arbre(v3, arbre(),
arbre()), arbre(v4, arbre(), arbre()))

Jacques Le Maitre I41 : Types de donnes 91


Oprations primitives sur les arbres
binaires (1)
On note :
Arbre(T) : le type des arbres binaires de valeurs de type T

Jacques Le Maitre I41 : Types de donnes 92


Oprations primitives sur les arbres
binaires (2)
Cration dun arbre binaire vide
cons-arbre-vide : Vide Arbre(T)
cons-arbre-vide : ()
Cration dun arbre binaire non vide
cons-arbre : T Arbre(T) Arbre(T) Arbre(T)
cons-arbre : (v, a1, a2) arbre (v, a1, a2)
Test darbre vide
arbre-vide : Arbre(T) Boolen
arbre-vide : arbre() vrai
arbre-vide : arbre(v, a1, a2) faux

Jacques Le Maitre I41 : Types de donnes 93


Oprations primitives sur les arbres
binaires (3)
Racine dun arbre
racine : Arbre(T) T
racine : () erreur !
racine : arbre(v, a1, a2) v
Sous-arbre gauche de la racine dun arbre
gauche : Arbre(T) Arbre(T)
gauche : () erreur !
gauche : arbre(v, a1, a2) a1
Sous-arbre droit de la racine dun arbre
droit : Arbre(T) Arbre(T)
droit : () erreur !
droit : arbre(v, a1, a2) a2

Jacques Le Maitre I41 : Types de donnes 94


Autres oprations
Nous en tudierons 4 :
test de feuille (racine dun arbre binaire dont les deux sous-arbres
sont vides),
hauteur dun arbre binaire,
construction dun arbre binaire de recherche par insertion, dans un
arbre binaire de recherche, dune valeur relativement une
relation dordre donne,
recherche dune valeur dans un arbre binaire de recherche.

Jacques Le Maitre I41 : Types de donnes 95


Notre reprsentation dun arbre binaire
Un arbre binaire non vide de racine v est reprsent par un
nud qui contient :
la valeur v,
lidentifiant du sous-arbre gauche,
lidentifiant du sous-arbre droit.
Un nud a un identifiant.
Un arbre binaire a un identifiant qui est :
lidentifiant du nud qui contient sa racine, si cet arbre nest pas
vide,
lidentifiant nul, si cet arbre est vide (on peut voir lidentifiant nul
comme celui dun nud factice de contenu vide).

Jacques Le Maitre I41 : Types de donnes 96


Reprsentation dun arbre binaire

nud
v1

valeur
v2

feuille
v3 v4 arbre vide

Jacques Le Maitre I41 : Types de donnes 97


cons-arbre-vide

cons_arbre_vide()

nul

Jacques Le Maitre I41 : Types de donnes 98


cons-arbre

cons_arbre(v, a1, a2)

a1 a2

Jacques Le Maitre I41 : Types de donnes 99


arbre-vide

a arbre_vide(a) vrai

a v

arbre_vide(a) faux

Jacques Le Maitre I41 : Types de donnes 100


racine

a v

racine(a) v

Jacques Le Maitre I41 : Types de donnes 101


gauche

g
gauche(a) g

Jacques Le Maitre I41 : Types de donnes 102


droit

d
droit(a) d

Jacques Le Maitre I41 : Types de donnes 103


feuille
Une feuille est la racine dun arbre binaire
dont le sous-arbre gauche et le sous-arbre droit sont vides.

feuille(a1) faux

a1
feuille(a2) vrai

a2

Jacques Le Maitre I41 : Types de donnes 104


hauteur-arbre
La hauteur dun arbre a hauteur_arbre(a) 0
binaire est gale 0 sil
est vide ou au nombre de
a
nuds 1 de sa plus
longue branche sinon. hauteur_arbre(a) 0
On a :
hauteur(a) = 0, si a est
vide ou si la racine de a
est une feuille, a
hauteur(a) = 1 +
max(hauteur(g),
hauteur_arbre(a) 1
hauteur(d)), si a est un
arbre non vide de sous-
arbre gauche g et de
sous-arbre droit d.

Jacques Le Maitre I41 : Types de donnes 105


Parcours prfixe dun arbre binaire
1

2 3

parcours-prfixe(a) =
si arbre-vide(a) alors
4 5 traiter racine(a)
parcours-prfixe(gauche(a))
parcours-prfixe(droit(a))

Parcours prfixe
racine
sous-arbre gauche
sous-arbre droit

Jacques Le Maitre I41 : Types de donnes 106


Parcours infixe dun arbre binaire
2

1 4

parcours-infixe(a) =
si arbre-vide(a) alors
3 5 parcours-infixe(gauche(a))
traiter racine(a)
parcours-infixe(droit(a))

Parcours infixe
sous-arbre gauche
racine
sous-arbre droit

Jacques Le Maitre I41 : Types de donnes 107


Parcours postfixe dun arbre binaire
5

1 4

parcours-postfixe(a) =
si arbre-vide(a) alors
2 3 parcours-postfixe(gauche(a))
parcours-postfixe(droit(a))
traiter racine(a)

Parcours postfixe
sous-arbre gauche
sous-arbre droit
racine

Jacques Le Maitre I41 : Types de donnes 108


Parcours en largeur dun arbre binaire

1 parcours-en-largeur(a) =
si arbre-vide(a) alors
f = file-vide
entrer(f, a)
2 3 faire
a = sortir(f)
traiter racine(a)
g = gauche(a)
4 5 6 7
d = droit(a)
si arbre-vide(g) alors
entrer(f, g)
si arbre-vide(d) alors
entrer(f, d)
Parcours en largeur
jusqu file-vide(f)
niveau par niveau

Jacques Le Maitre I41 : Types de donnes 109


Modification dun arbre binaire
On notera quil ny a pas de primitives dinsertion ou de
suppression de sous-arbres, ou bien de remplacement de
la valeur de la racine, comme cest le cas pour les maillons
dune liste linaire :
Il nest donc pas possible de modifier une arbre en place .
La solution est de construire, partir de larbre modifier,
un nouvel arbre comportant qui peut partager des sous-
arbres avec l'arbre initial.

Jacques Le Maitre I41 : Types de donnes 110


Modification par reconstruction
cons_arbre(racine(a), gauche(a), cons_arbre(racine(droit(a)), droit(droit(a)), arbre_vide()));

a v1 nouvel arbre v1

v2 a v3 partage de sous-arbre v3

v4 v5
partage de sous-arbre

Jacques Le Maitre I41 : Types de donnes 111


Arbres binaires de recherche
Un arbre binaire de recherche est
un arbre binaire dans lequel les
valeurs sont places relativement 22
une relation dordre , de la faon
suivante.
Pour tout sous-arbre de racine r : 56
les valeurs contenues dans le sous-arbre
gauche, sont les valeurs v telles que
v r,
29 75
les valeurs contenues dans le sous-arbre
droit sont les valeurs v telles que v r.
La recherche dune valeur ne
ncessite que le parcours de la
branche laquelle appartient cette est la relation
valeur. sur les entiers

Jacques Le Maitre I41 : Types de donnes 112


Insertion et recherche dune valeur dans
un arbre binaire de recherche
Linsertion et la recherche dune valeur dans un arbre binaire de
recherche sont ralises par les fonctions cons-arbre-recherche et chercher.
Dans le cas gnral, les valeurs de larbre sont structures et sont
ordonnes par rapport la valeur de lune de leurs composantes que nous
appellerons la cl. Par exemple, le nom ou lge dune personne.
Lorsque les valeurs de larbre sont atomiques, des nombres par exemple, la
cl est gale la valeur elle-mme.
Soit T le type des valeurs de larbre binaire de recherche et K celui de leurs
cls.
En insertion, il faudra fournir une fonction de comparaison de deux
valeurs, dfinie de la faon suivante :
compvv : T T {1, 0, 1}
compvv : (v1, v2) 1 si cl(v1) cl(v2), 0 si cl(v1) = cl(v2), 1 si cl(v1) cl(v2)
En recherche, il faudra fournir une fonction de comparaison dune cl et
dune valeur, dfinie de la faon suivante :
compkv : K T {1, 0, 1}
compkv : (k, v) 1 si k cl(v), 0 si k = cl(v), 1 si k cl(v)

Jacques Le Maitre I41 : Types de donnes 113


cons-arbre-recherche (1)
cons-arbre-recherche : Arbre(T) T (T T {1, 0, 1}) Arbre(T)
cons-arbre-recherche (a, v, compvv) =
si arbre-vide(a) alors
cons-arbre(v, cons-arbre-vide(), cons-arbre-vide())
sinon
soit a = (r, g, d) dans
si compvv(v, r) 0 alors
cons-arbre(r, cons-arbre-recherche(g, compvv, v), d)
sinon
cons_arbre(r, g, cons-arbre-recherche(d, compvv, v))

Jacques Le Maitre I41 : Types de donnes 114


cons-arbre-recherche (2)

22
cons-arbre-recherche
a
(a, 22, compvv)

Relation dordre : sur les entiers

Jacques Le Maitre I41 : Types de donnes 115


cons-arbre-recherche (3)

22

a 22
cons-arbre-recherche
(a, 56, compvv) 56

Relation dordre : sur les entiers

Jacques Le Maitre I41 : Types de donnes 116


cons-arbre-recherche (4)
22

a 22

56
cons-arbre-recherche
56 (a, 29, compvv)
29

Relation dordre : sur les entiers

Jacques Le Maitre I41 : Types de donnes 117


cons-arbre-recherche (5)
a 22 22

56 56
cons-arbre-recherche
(a, 75, compvv)
29 29 75

Relation dordre : sur les entiers

Jacques Le Maitre I41 : Types de donnes 118


Parcours ordonn des valeurs dun arbre binaire
de recherche
(ordre alphabtique)

Pour accder aux valeurs t 3


dun arbre binaire de
recherche dans lordre
p 2 y 5
selon lequel cet arbre a t
construit, il suffit de
parcourir larbre en ordre e 1 s 4
infixe .

e p t s y
Jacques Le Maitre I41 : Types de donnes 119
chercher (1)
chercher : Arbre(T) K (K T {1, 0, 1}) Arbre(T)
chercher(a, k, compkv) =
si arbre_vide(a ) alors
a
sinon
soit a = (r, g, d) dans
si compkv (k, r) < 0 alors
chercher(g, k, compkv)
sinon
si compkv(k, r) = 0 alors
a
sinon
chercher(d, k, compkv)

Jacques Le Maitre I41 : Types de donnes 120


chercher (2)
Si la recherche a russi, la fonction chercher retourne le
sous-arbre dont la racine a pour cl la cl recherche.
Si cette cl nest pas unique, il faudra relancer la recherche
dans le sous-arbre gauche de ce sous-arbre
Si la recherche a chou, la fonction chercher retourne un
arbre vide.

Jacques Le Maitre I41 : Types de donnes 121


chercher (3)
a 22

a 56
chercher(a, 29) chercher(a, 29)

29 75

Relation dordre : sur les entiers

Jacques Le Maitre I41 : Types de donnes 122


chercher (4)
22

a 56
chercher(a, 29) chercher(a, 29)

a 29 75

Relation dordre : sur les entiers

Jacques Le Maitre I41 : Types de donnes 123


chercher (5)
22

56
chercher(a, 29) a
chercher(a, 29)

a 29 75

Relation dordre : sur les entiers

Jacques Le Maitre I41 : Types de donnes 124


chercher (6)
a 22

a
56
chercher(a, 12) chercher(a, 12)

29 75

Relation dordre : sur les entiers

Jacques Le Maitre I41 : Types de donnes 125


chercher (7)
22

a
56
chercher(a, 12) a (chec)

29 75

Relation dordre : sur les entiers

Jacques Le Maitre I41 : Types de donnes 126


Cot dune recherche
Le cot dune recherche peut-tre mesur en nombre de nuds
parcourus.
La recherche dune valeur se fait le long dune seule branche.
Le cot maximum est donc gal h + 1, si h est la hauteur de
larbre.
Si un arbre contient n nuds :
sa hauteur maximum est gale n 1 lorsque larbre na quune seule
branche.
sa hauteur minimum est gale log2(n + 1) 1 lorsque larbre est
quilibr (toutes les branches ont la mme longueur).
Le cot de recherche est donc compris entre n et log2(n + 1). En
moyenne, il est logarithmique ((log n)).

Jacques Le Maitre I41 : Types de donnes 127


Reprsentation d'un arbre binaire en C
struct noeud typedef struct noeud *Arbre;
{ struct noeud
valeur v1 {
gauche void *valeur;
droit Arbre gauche;
} Arbre droit;
};
struct noeud struct noeud
{ {
valeur v2 valeur v3
gauche NULL gauche NULL
droit NULL droit
} }
NULL
struct noeud arbre()
(v1, arbre(v2, {
arbre(), valeur v4
arbre(v4, arbre(), arbre)), gauche NULL
arbre(v3, arbre(), arbre())) droit NULL
}
Jacques Le Maitre I41 : Types de donnes 128
Interface
La dclaration du type Arbre ainsi que les dclarations
des fonctions de linterface sont enregistrs dans le fichier
TD-arbre-binaire.h.
Les dfinitions des fonctions de linterface sont
enregistres dans le fichier TD-arbre-binaire.c.

Jacques Le Maitre I41 : Types de donnes 129


Fichier TD-arbre-binaire.h (1)
#ifndef TD_ARBRE_BINAIRE
#define TD_ARBRE_BINAIRE

#include <stdlib.h>
#include <stddef.h>
#include "erreur.h"

typedef struct noeud *Arbre;

struct noeud
{
void *valeur;
Arbre gauche;
Arbre droit;
};

Jacques Le Maitre I41 : Types de donnes 130


Fichier TD-arbre-binaire.h (2)
Arbre cons_arbre_vide(void);
Arbre cons_arbre(void *v, Arbre g, Arbre d);
void *racine(Arbre a);
Primitives
Arbre gauche(Arbre a);
Arbre droit(Arbre a);
int arbre_vide(Arbre a);

int feuille(Arbre a);


int hauteur_arbre(Arbre a);
Arbre cons_arbre_recherche(Arbre a, void *v, int (*comp)(const
void *, const void *));
Arbre chercher(Arbre a, void *cle, int (*comp)(const void *,
const void *));

#endif

Jacques Le Maitre I41 : Types de donnes 131


Construire un arbre binaire vide
Arbre cons_arbre_vide(void)
{
return NULL;
}

Jacques Le Maitre I41 : Types de donnes 132


Construire un arbre binaire de racine r, de sous-
arbre gauche g et de sous-arbre droit d
Arbre cons_arbre(void *v, Arbre g, Arbre d)
{
Arbre a;
a = (Arbre) malloc(sizeof(struct noeud));
if (a == NULL)
erreur("cons_arbre");
a->valeur = v;
a->gauche = g;
a->droit = d;
return a;
}

Jacques Le Maitre I41 : Types de donnes 133


Larbre binaire a est-il vide ?
int arbre_vide(Arbre a)
{
return a == NULL;
}

Jacques Le Maitre I41 : Types de donnes 134


Racine dun arbre binaire a
void *racine(Arbre a)
{
if (arbre_vide(a))
erreur("racine");
return a->valeur;
}

Jacques Le Maitre I41 : Types de donnes 135


Sous-arbre gauche de la racine dun arbre
binaire a
Arbre gauche(Arbre a)
{
if (arbre_vide(a))
erreur("gauche");
return a->gauche;
}

Jacques Le Maitre I41 : Types de donnes 136


Sous-arbre droit de la racine dun arbre
binaire a
Arbre droit(Arbre a)
{
if (arbre_vide(a))
erreur("droit");
return a->droit;
}

Jacques Le Maitre I41 : Types de donnes 137


La racine de larbre binaire a est-elle une
feuille ?
int feuille(Arbre a)
{
if (arbre_vide(a))
erreur("feuille");
return arbre_vide(gauche(a)) && arbre_vide(droit(a));
}

Jacques Le Maitre I41 : Types de donnes 138


Hauteur de larbre binaire a
int hauteur_arbre(Arbre a)
{
int hg, hd;
if (arbre_vide(a) || feuille(a))
return 0;
hg = hauteur_arbre(gauche(a));
hd = hauteur_arbre(droit(a));
if (hg > hd)
return 1 + hg;
else
return 1 + hd;
}

Jacques Le Maitre I41 : Types de donnes 139


Construire un arbre binaire de recherche par insertion dune
valeur v dans un arbre binaire de recherche a en utilisant la
fonction comp de comparaison de deux valeurs
Arbre cons_arbre_recherche(Arbre a, void *v,
int (*comp)(const void *, const void *))
{
void *r;
Arbre g, d;
if (arbre_vide(a))
return cons_arbre(v, NULL, NULL);
r = racine(a);
g = gauche(a);
d = droit(a);
if (comp(v, r) <= 0)
return cons_arbre(r, cons_arbre_recherche(g, v, comp), d);
else
return cons_arbre(r, g, cons_arbre_recherche(d, v, comp));
}

Jacques Le Maitre I41 : Types de donnes 140


Chercher une valeur de cl cle dans un arbre binaire de
recherche a en utilisant la fonction comp de comparaison
dune cl et dune valeur
Arbre chercher(Arbre a, void *cle,
int (*compvv)(const void *, const void *))
{
void *v;
int c;
if (arbre_vide(a))
return a;
c = comp(cle, racine(a));
if (c < 0)
return chercher(gauche(a), cle, comp);
if (c == 0)
return a;
return chercher(droit(a), cle, comp);
}

Jacques Le Maitre I41 : Types de donnes 141


Autres oprations
Parcours d'un arbre binaire
prfixe
infixe
suffixe
en largeur

Jacques Le Maitre I41 : Types de donnes 142


Parcours prfixe d'un arbre binaire a
(racine gauche droit)
void parcours_prefixe(Arbre a)
{
if (!arbre_vide(a))
{
Traiter la valeur contenue dans la racine de l'arbre a
parcours_prefixe(gauche(a));
parcours_prefixe(droit(a));
}
}

Jacques Le Maitre I41 : Types de donnes 143


Parcours infixe d'un arbre binaire a
(gauche racine droit)
void parcours_infixe(Arbre a)
{
if (!arbre_vide(a))
{
parcours_infixe(gauche(a));
Traiter la valeur contenue dans la racine de l'arbre a
parcours_infixe(droit(a));
}
}

Jacques Le Maitre I41 : Types de donnes 144


Parcours suffixe d'un arbre binaire a
(gauche droit - racine)
void parcours_suffixe(Arbre a)
{
if (!arbre_vide(a))
{
parcours_suffixe(gauche(a));
parcours_suffixe(droit(a));
Traiter la valeur contenue dans la racine de l'arbre a
}
}

Jacques Le Maitre I41 : Types de donnes 145


Parcours en largeur d'un arbre binaire a
void parcours_en_largeur(Arbre a)
{
File f;
Arbre g, d;
if (!arbre_vide(a))
{
f = creer_file();
entrer(f, a);
do
{
a = arbre(sortir(f));
Traiter la valeur contenue dans la racine de l'arbre a
g = gauche(a);
d = droit(a);
if (!arbre_vide(g))
entrer(f, g);
if (!arbre_vide(d))
entrer(f, d);
}
while (!file_vide(f));
}
}

Jacques Le Maitre I41 : Types de donnes 146

Vous aimerez peut-être aussi