Documente Academic
Documente Profesional
Documente Cultură
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
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
*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
end.
Le mme exemple en C :
int main()
{
char *p;
...
p = malloc( sizeof(char) );
*p = 'A';
free(p);
...
return 0;
}
- 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
/* 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
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
v5
Un maillon
de la liste
Tte
La structure d'un maillon est alors :
v6
Queue
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
var
T : tableau[N] de Tmaillon ;
Init( )
POUR i 1,N
T[i].vide VRAI
FP
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).
10
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
adr
9
0
0
10
1
7
5
4
3
v2
0
11
v1
2
1
v3
5
6
4
11