Sunteți pe pagina 1din 11

Les Listes Linaires Chanes (LLC)

Plan
1. Introduction
2. Allocation Statique et Dynamique
3. Dfinition d'une LLC
4. Quelques oprations sur les LLC
5. Listes particulires
6. Implmentation en contigu
1) Introduction
L'espace mmoire occup par une structure de donnes dynamique est variable.
C'est intressant pour reprsenter des ensembles tailles variables.
On peut donc agrandir ou rtrcir la taille de l'ensemble durant l'excution du programme.
Certains problmes ncessitent la gestion d'un ensemble dynamique.
Exemple:
Trouver tous les nombres premiers <= n (avec n un paramtre donn) et les stocker en mmoire.
Le problme ici est la taille de la structure utilise pour sauvegarder les nombres premiers. Un
tableau ne conviendrait pas car on a aucune ide sur la taille rserver au dpart.
2) Notion d'allocation mmoire
- Variables
La Mmoire Centrale (MC) est forme par des cases numrotes. Chaque case peut stocker,
gnralement, un octet (8 bits).
Une variable est une zone contigu en MC (une case ou un ensemble de cases qui se suivent). Sa
taille (en nombre de cases) dpend du type de la variable (ex: un entier occupe 4 cases, un rel
occupe 8 cases, ...etc). L'adresse d'une variable est le numro de sa premire case.
Exemple:
En langage Pascal on peut dclarer une variable entire comme suit:
var
x : integer;
En langage C on aura:
int x;
Dans cet exemple, x est le nom donn pour rfrencer l'emplacement mmoire associ la variable
(par exemple la case mmoire d'adresse 100)
x
100

Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

Quand on affecte une valeur (par ex 10) x. la case numro 100 contiendra cette mme valeur:
en Pascal : x := 10; ou alors en C : x = 10;
On dit alors que le contenu de l'adresse 100 est 10
x
10
100
- Pointeurs
Un pointeur est une variable qui peut contenir des adresses mmoires
Exemple :
En Pascal on peut dclarer un pointeur vers un entier comme suit:
var
p : ^integer;
Ou bien en C :
int *p;
p
200
D'aprs cette dclaration, on peut affecter la variable p l'adresse d'une variable de type entier.
En C, l'expression &v retourne l'adresse de la variable v. En Pascal standard, il n'existe pas un
moyen de rcuprer l'adresse d'une variable, part l'utilisation de l'allocation dynamique (voir plus
loin). Cependant certains compilateur Pascal (non standards) offrent un tel mcanisme (Addr(v) en
turbo-pascal retourne l'adresse de la variable v)
Donc si on crit par exemple, en turbo-pascal :
p := Addr(x);
Ou bien en C :
p = &x;
On aura dans p l'adresse de x :
p
200

100

on dit alors que p pointe x.


Maintenant, on peut par exemple modifier la valeur de x indirectement (sans faire rfrence x).
En Pascal l'expression p^ fait rfrence la variable pointe par p.
Il en est de mme en C, avec l'expression *p
Si on crit en Pascal :
p^ := 20;
Ou bien en C :
Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

*p = 20;
La valeur de x sera alors modifie (par une affectation indirecte)
p
200

100

x
100

10 20

Une telle utilisation des pointeurs (modifications par indirection) est par exemple utile en C pour
crire des fonctions qui peuvent modifier leurs paramtres (passage par adresse).
Il y a une autre utilisation des pointeurs, utile en Pascal et en C : l'allocation dynamique de
variables.
- Allocation de variables
Allocation de variables veut dire cration de variables. Donc rservation d'espace mmoire en
associant chaque variable l'adresse d'une zone en mmoire.
Il existe 2 types d'allocation: statique (gre automatiquement par le systme) et dynamique (gre
manuellement par le programmeur).
Toutes les variables dclares reprsentent des variables alloues statiquement :

Les variables du programme principales d'un programme Pascal ou les variables globales
d'un programme C sont automatiquement cres au dbut de l'excution et dtruites la fin
de l'excution.
Les variables d'une procdure ou fonction (ainsi que les paramtres d'appels) sont
automatiquement cres au dbut de chaque appel et dtruites chaque retour de procdure
ou fonction.

Il existe des fonctions prdfinies en Pascal ou en C pour crer de nouvelles variables durant
l'excution d'un programme et pour les dtruire aussi, c'est l'allocation dynamique :
En Pascal, la procdure new(p) alloue une nouvelle variable et affecte son adresse la variable p.
Le type de la nouvelle variable est celui spcifi dans la dclaration de p. La procdure dispose(p)
dtruit la variable pointe par p.
En C, la fonction malloc( nb_octets ) alloue une zone mmoire de taille nb_octets et retourne son
adresse comme rsultat. La fonction free(p) dtruit la variable pointe par p.
Exemple en Pascal:
var
p : ^char;
begin

{ allocation automatique de la variable p de type pointeur }


new(p);
p^ := 'A';
dispose(p);

end.

{ allocation manuelle d'une variable caractre pointe par p }


{ utilisation indirecte de la variable dynamique }
{ destruction manuelle de la variable dynamique }
{ destruction automatique de la variable p }

Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

Le mme exemple en C :
int main()
{
char *p;
...
p = malloc( sizeof(char) );
*p = 'A';
free(p);
...
return 0;

/* allocation automatique de p de type pointeur */


/* allocation manuelle d'une variable de mme taille
qu'un caractre : sizeof( type ) retourne le nb d'octets
ncessaire pour reprsenter une variable de ce type */
/* utilisation indirecte de la variable dynamique */
/* destruction manuelle de la variable dynamique */
/* destruction automatique de la variable p */

}
- Remarques
* Les constantes pointeurs NIL (en Pascal) ou bien NULL ou 0 (en C) indiquent l'absence d'adresse.
Donc, par exemple en Pascal, l'affectation p := NIL, veut dire que p ne pointe aucune variable.
* Il ne faut jamais utiliser l'indirection (^ en pascal ou * en C) avec un pointeur ne contenant pas
une adresse valide, il y aura alors une erreur de segmentation.
Exemple :
var
p : ^integer;
begin
...
{ le contenu de p est pour le moment indtermin : une adresse quelconque de la mmoire }
p^ := 10;
{ erreur l'excution; affectation d'un entier (10) dans une zone indtermine }
{ p ne pointe aucune variable de type entier }
...
end.
* De mme il est interdit de rfrencer une variable dynamique aprs l'avoir dtruite :
var
p : ^integer;
begin
new( p );
{ le contenu de p est l'adresse d'une variable dynamique nouvellement cre }
p^ := 10;
{ l'affectation est correcte, la zone concerne contient une variable de type entier }
dispose( p );
{ destruction de la variable dynamique, maintenant p pointe une zone quelconque }
p^ := 20;
{ erreur l'excution; affectation d'un entier (20) dans une zone indtermine }
end.
Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

* Les variables dynamiques peuvent tre de n'importe quel type, simple ou complexe. Voici un
exemple en Pascal montrant l'allocation dynamique de tableaux :
type
T_tab = array[1..100] of integer;
{ def d'un type tableau de 100 entiers }
{ il n'y a aucune allocation ici, T_tab n'est pas une variable }
var
p : ^T_tab;
i : integer;
begin { allocation automatique de p (un pointeur) et de i (un entier) }
...
{ pour le moment il n'y a aucun tableau allou }
{ on peut en allouer un avec l'opration new }
new( p );
{ un tableau de 100 entiers a t allou dynamiquement, son adresse est dans p }
...
{ on manipule le tableau l'aide de l'indirection p^ }
p^[1] := 10;
p^[2] := 3;
p^[3] := p^[1] * 2 + 5;
...
{ on peut dtruire le tableau quand on n'en a plus besoin }
dispose( p );
{ maintenant le tableau n'existe plus, on n'a plus le droit de manipuler p^ }
...
{ mais on peut crer un autre tableau et le manipuler en utilisant le mme pointeur }
new( p );
for i:=1 to 100 do
p^[i] := 5432;
...
end.
* Une variable dynamique n'a pas de nom, on ne peut la manipuler qu' travers un pointeur qui
contiendrait son adresse. Si on perd cette adresse, on ne peut plus accder au contenu de la variable
dynamique.
3) Dfinition d'une Liste Linaire Chane (LLC)
Une Liste Linaire Chane est une structure de donnes (le plus souvent dynamique) pour
reprsenter un ensemble de valeurs. Ces valeurs sont chanes entre elles formant une suite :

v1
Tte

v2

v3

val adr
v4

...

Un maillon
de la liste

vn
nil

Chaque valeur v de l'ensemble est stocke dans un maillon (gnralement une variable dynamique)
Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

Un maillon est une structure 2 champs :


{ val : de type quelconque , adr : pointeur vers le prochain maillon de la liste }
Dans le dernier maillon de la liste, le champs adr contient le pointeur NIL (indiquant par convention
la fin de la liste).
L'adresse du 1er maillon (la tte de la liste) est importante. Elle doit toujours tre sauvegarde dans
une variable pour pouvoir manipuler la liste.
Si la liste est vide (ne contient aucun maillon), la tte doit alors tre positionne NIL.
- Le modle des LLC
On dfinit un ensemble d'oprations que l'on va utiliser pour crire des algorithmes sur les listes
sans expliciter les dtails d'implmentation des listes. Cet ensemble d'oprations s'appelle le modle
des listes linaires chanes (MLLC) :
* Allouer( p ) - procdure qui alloue un nouveau maillon et affecte son adresse dans le pointeur p.
Les champs val et adr du nouveau maillon sont indtermins.
* Librer( p ) - procdure qui dtruit le maillon point par p.
* Aff-val( p,v ) - procdure qui affecte v dans le champs val du maillon point par p.
* Aff-adr( p,q ) - procdure qui affecte q dans le champs adr du maillon point par p.
* Valeur( p ) : typeqlq - fonction qui retourne le contenu du champs val du maillon point par p.
* Suivant( p ) : pointeur - fonction qui retourne le contenu du champs adr du maillon point par p.
Exemple d'utilisation : voici une procdure qui insre une valeur 'v' dans une liste 'L' ordonne en
ordre croissant :
procedure ins_ord( v : typeqlq; var L : ptr )
/* insre v dans L, le rsultat (ventuellement la nouvelle tte) est dans L */
var
p, q, n : ptr;
trouv : bool;
debut
/* on commence par rechercher l'endroit o doit tre insre v pour que la liste
reste ordonne (parcours squentiel jusqu' trouver une valeur >= v) */
trouv FAUX;
/* boolen indiquant la fin du parcours */
p L;
/* pointeur pour parcourir les maillons de la liste L */
q NIL;
/* pointeur pour garder le prcdent de p */
TQ (p <> NIL) ET (Non trouv)
SI ( v <= Valeur(p) )
trouv VRAI
SINON
q p;
/* on sauvegarde dans q l'adr du maillon, */
p Suivant(p);
/* avant de passer au prochain avec p. */
FSI
FTQ;
Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

/* quand on sort de cette boucle TQ, on pourra insrer v entre les maillons points
par q et p, avec les cas particuliers suivants :
si on sort avec q=NIL, alors v sera insre au dbut de la liste
si on sort avec p=NIL, alors v sera insre la fin de la liste */
Allouer( n );
/* n pointe maintenant un nouveau maillon */
Aff-val( n, v );
/* on y affecte la valeur v */
Aff-adr( n, p );
/* le suivant de n est maintenant p (mme si c'est NIL) */
SI (q <> NIL)
/* s'il existe un maillon qui prcde p :
Aff-adr( q, n ) /* le suivant de q devient alors n */
SINON
/* sinon (q=NIL) :
Ln
/* n devient la nouvelle tte de la liste */
FSI
fin
4) Quelques oprations sur les LLC
- accs par valeur:
Il s'agit de rechercher (squentiellement partir de la tte) une valeur v dans la liste.
- accs par position:
Il s'agit de rechercher (squentiellement partir de la tte) le maillon (son adresse) qui se trouve la
position donne. La position est le numro d'ordre du maillon dans la liste (entier)
- insertion d'une valeur (v) une position donne (i)
Allouer un nouveau maillon contenant v et l'insrer dans la liste de telle sorte qu'il se retrouve la
ieme position.
- insertion d'une valeur (v) dans une liste ordonne
Allouer un nouveau maillon contenant v et l'insrer dans la liste de telle sorte que la liste reste
ordonne aprs l'insertion.
- suppression du maillon se trouvant une position donne (i)
Rechercher par position le maillon i et le librer. Le maillon prcdent (s'il existe) doit tre mis
jour pour pointer le suivant de i.
- suppression d'une valeur v dans la liste
Rechercher par valeur et supprimer le maillon trouv en mettant jour le prcdent (s'il existe).
Si la liste contient plusieurs occurrences de la mme valeur, on pourra les supprimer en faisant un
seul parcours de la liste.
- trier une liste
Les mme algo de tri utilisable pour les tableaux, en prenant en compte que l'accs par position
cote beaucoup plus cher que dans un tableau.
Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

- fusion (ou interclassement) de 2 listes ordonnes


A partir de 2 listes ordonnes, construire une liste ordonne contenant tous leurs lments.
On peut aussi changer les champs 'adr' des maillons existant dans les 2 listes pour former qu'une
seule liste ordonne (sans allouer de nouveaux maillons).
- clatement d'une liste en 2 listes distinctes
A partir d'une liste L et d'un critre (un prdicat) donns, on construit 2 listes, l'une contenant toutes
les valeurs de L vrifiant le critre, l'autre, celles qui ne le vrifient pas.
- construction d'une liste partir de n valeurs donnes
- destruction d'une liste en supprimant tous ses maillons
Ces oprations de haut niveau (recherche, insertion, suppression, ...) dfinissent en fait le type
abstrait Liste .
5) Listes particulires
- Listes circulaires
C'est une liste o le dernier maillon pointe le premier, formant ainsi un cercle.
La tte de la liste est l'adresse de n'importe quel maillon de la liste circulaire.
Le mme modle des LLC est utilis pour crire des algorithmes sur ce type de listes.
v3
v2

v4

v1

V5

Tte

8
V

v6

v7
- Listes bidirectionnelles
Ce sont des listes que l'on peut parcourir dans les deux sens : de gauche droite et de droite
gauche.
Pour cela on rajoute dans chaque maillon un deuxime pointeur indiquant l'adresse du maillon
prcdent.
Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

v1

v2

v3

adrg val adrd


v4

v5

Un maillon
de la liste

Tte
La structure d'un maillon est alors :

v6
Queue

{val : typeqlq, adrg : ptr, adrd : ptr }

Souvent on sauvegarde les adresses du 1er et du dernier maillon (tte et queue) pour simplifier les
parcours dans les deux sens.
Le modle des listes bidiectionnelles est presque le mme que celui des LLC sauf que Aff-adr(p,q)
est remplace par Aff-adrg(p,q) et Aff-adrd(p,q). De plus la fonction de type ptr 'Precedent(p)' est
rajoute pour retourner le contenu du champs 'adrg' alors que la fonction 'Suivant(p)' retourne le
champs 'adrd'.
6) Implmentation des listes en contigu
Il s'agit d'implmenter le modle des LLC sans utiliser d'allocation dynamique.
C'est donc l'utilisation d'un tableau (un espace contigu) pour simuler la mmoire rserve
l'allocation dynamique. Chaque lment du tableau peut tre utilis pour reprsenter un maillon
allou. Les indices du tableau reprsentent alors les adresses de maillons. Une valeur spciale (par
exemple 0 ou -1) sera utilise pour indiquer la constante NIL.
Voici un implmentation simple du modle des LLC avec un tel tableau :
val
N

vide
V

5
4
3
2
1

V
V
F
V
F
F
V

v2
v1
v3

type
ptr = entier;
Tmaillon = struct
val : Tqlq;
vide : Booleen;
adr : entier
fin;

adr

2
5
0

// boolen utilis pour diffrencier entre case libre et alloue

Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

var
T : tableau[N] de Tmaillon ;
Init( )
POUR i 1,N
T[i].vide VRAI
FP

// l'espace contigu sous forme de tableau. N est une constante

// procdure d'initialisation : toutes les cases sont au dpart libres

Allouer( var p:ptr )


// On recherche la premire case libre et on l'alloue.
p 1;
trouv Non T[p].vide;
TQ p<N et Non trouv
// parcours squentiel !!!
p p+1;
trouv Non T[p].vide
FTQ
SI Non trouv
p0
SINON
T[p].vide FAUX
FSI
Liberer( p:ptr )
T[p].vide VRAI

// Repositionne une case l'tat libre

Aff-val( p:ptr; v:Tqlq )


T[p].val v

// MAJ du champs val d'un maillon occup

Aff-adr( p:ptr; q:ptr )


T[p].adr q

// MAJ du champs adr d'un maillon occup

Valeur( p:ptr ) : Tqlq


Valeur T[p].val

// Consultation du champs val d'un maillon occup

Suivant( p:ptr ) : ptr


Suivant T[p].adr

// Consultation du champs adr d'un maillon occup

Cette implmentation est simple mais elle n'est pas trs efficace. A chaque fois qu'on alloue un
nouveau maillon, la procdure 'Allouer(...)' ralise un parcours squentiel. Cela peut tre trs
pnalisant quand la taille du tableau est grande.
Il existe une autre implmentation, plus efficace en vitant de faire un parcours squentiel lors de
l'allocation d'un maillon. Toutes les oprations peuvent tre implmentes sans utiliser de boucle,
car on maintient une liste particulire de cases libres dans le tableau T.
Initialement toutes les cases sont chanes entre elles dans cette liste de cases libres.
A chaque allocation d'un maillon (procdure Allouer(p)), on retire de cette liste la premire case (la
tte de liste).
A chaque libration d'un maillon (procdure Librer(p)), on rajoute la case libre au dbut de la
liste des cases libres (insertion au dbut d'une liste).

Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

10

Les autres oprations du modle restent pratiquement inchanges.


Le champs 'vide' devient inutile.
Voici un exemple illustrant une telle implmentation :
val
11
10
9
8
Liste des cases libres

w2
w1

7
6

adr
9
0
0
10
1
7

5
4
3

v2

2
11

v1

2
1

v3

5
0
4

Dans cet exemple, on remarque que 5 cases sont occupes parmi les 11 cases de la table (les cases
d'indices 2, 3, 5, 8 et 10). Ces 5 cases semblent former 2 listes linaires chanes distinctes. L'une de
tte 3 (v1v2v3) et l'autre de tte 8 (w1w2).
Les autres cases ne sont pas occupes, elles sont chanes entre elles formant une liste de cases libre
dont la tte est la case d'indice 6. La liste est : 6714119
Si le maillon contenant la valeur v3 (case d'indice p=2), vient tre libr (suite par exemple une
suppression de v3 dans la liste de tte 3), l'indice 2 sera alors insr en tte de la liste des cases
libres par la procdure 'Librer(p)'. Ce qui donnera la configuration suivante :
val
11
10
9
8

w2
w1

7
6

Liste des cases libres

adr
9
0
0
10
1
7

5
4
3

v2

0
11

v1

2
1

v3

5
6
4

Hidouci W.K. / Listes Linaires Chanes / Structures de donnes (ALSDD) / ESI

11

S-ar putea să vă placă și