Chaque élément possède un successeur sauf la queue (son successeur est la valeur NULL).
5 2 -25 7 ...... 2
La notation linéaire [5, 2, -25, 7, ..., 2] représentera la liste qui contient cette séquence.
Les structures de données linéaires induisent une notion de séquence entre les éléments (1er, 2ème, 3ème, suivant, dernier, …).
En plus des opérations vues précédemment, d’autres peuvent être s’effectuent sur la liste elle-même tels que :
M. bada 1
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
a) Inconvénients
L’utilisation de tableaux possède quelques inconvénients :
! PBM1 : La dimension d’un tableau doit être définie lors des déclarations et ne peut donc pas être
modifié
o Solution : définir un tableau dont la taille sera suffisante pour accueillir le plus grand nombre
d’éléments
" PBM2 : gaspillage d’espace mémoire au cas des petites listes.
" PBM3 : si la taille maximum venait à être augmentée # il faudrait modifier le
programme et le recompiler
! Lorsqu’on veut retirer (ou insérer) un élément du tableau « en début », il est nécessaire de décaler tous
les éléments situés après l’élément supprimé.
b) Avantages :
Une liste chaînée est une structure linéaire qui n'a pas de dimension fixée à sa création.
Ses éléments de même type sont dispersés dans la mémoire et reliés entre eux par des pointeurs.
• Un élément ou maillon d’une liste est toujours une structure (Objet composé) avec deux ou plusieurs
champs :
o Un ou plusieurs champ = Valeur : contenant l’information
o Un champ = Adresse : donnant l’adresse du prochain élément.
La liste est accessible uniquement par sa tête de liste c’est-à-dire son premier élément.
3.2.1. Structure d’un élément : Un élément de la liste est une structure de donnée définie comme suite :
M. bada 2
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
Apres la déclaration de la structure élément, on peut créer des élément dynamiques en utilisant les pointeurs :
(*e).champ1 (*e).suivant
ou ou
e->champ1 e->suivant
e
#100
*e
La déclaration d’un tableau T de N éléments en C mène à la création de N+1 variables : T[0], T[1], ...,T[N-1] et T.
En quelque sorte, on peut dire que le tableau dans un programme n’est que l’adresse de la 1ere case = &T[0].
Comme pour les tableaux, une liste n’est que l’adresse du premier élément (Tête) de la liste.
a) Liste vide :
Une liste est dite vide si elle ne contient aucun élément. En d’autre terme, une liste vide est un pointeur qui
est égale à NULL.
Liste
Element* Liste ;
Liste =NULL ;
NULL
M. bada 3
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
Comme pour les tableaux, afin de parcourir une liste on a besoin de passer par touts les éléments en utilisant un index
(compteur ou position).
Pour afficher ou modifier le contenu d'un élément dans une liste chainée, l’index doit se pointer vers cet élément. Pour
cela il faut trouver un moyen qui permet de déplacer l’index d’un élément vers l’élément suivant.
Ex :
Un étudiant est définie par les champs suivant : N, Nom
Supposons qu’on a une liste d’étudiants déjà créée, dont la queue pointe vers null.
#100
M. bada 4
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
Liste Position
#100 #100
*position
#50 #200
(*position).suivant
Liste Position
#100 #50
*position
#50 #200
(*position).suivant
Position
Liste
#50
#100
M. bada 5
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
Position
Liste
NULL
#100
Liste
#100
#700
10 ‘’NV’’ NULL
Liste
Position
#100
#200
2 ‘’...’’ #700
3 ‘’aa’’ #50 6 ‘’...’’ #200
e
#700
10 ‘’NV’’ NULL
M. bada 6
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
Etudiant* e ;
e= (Etudiant*) = malloc (sizeof (Etudiant) ) ;
Etape 3 : parcourir la liste jusqu'à le dernier élément (position -> pointe le dernier élément « la
Queue » et pas NULL !!! ) # donc il faut faire avancer le pointeur position jusqu'à que son suivant
= NULL.
Etudiant* position ;
position= liste ;
while ( (*position).suivant != NULL )
{
position = (*position).suivant ;
}
(*position).suivant = e ;
Liste
#700
2 ‘’...’’ NULL
3 ‘’aa’’ #50 6 ‘’...’’ #200
2
#100 #50 #200
e 1
#700
10 ‘’NV’’ #100
*e
M. bada 7
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
Etape1 : création dynamique d’un nouvel élément (utilisation des pointeurs) + initialisation :
Etudiant* e ;
e= (Etudiant*) = malloc (sizeof (Etudiant) ) ;
(*e).suivant = liste ;
Liste = e ;
Directe : dans ce cas on va utiliser directement une variable « place » qui donne la position où l’on doit
insérer le nouvel élément.
Indirecte : dans ce cas, il faut trouver un élément particulier « ex : l’étudiant Mohammed » à partir du
quel on déterminera la position du nouvel élément : (avant ou après).
Etape1 : création dynamique d’un nouvel élément (utilisation des pointeurs) + initialisation
Etudiant* e ;
e= (Etudiant*) = malloc (sizeof (Etudiant) ) ;
Etudiant* position ;
position= liste ;
int i=0 ;
while ( i < K-2 )
{
position = (*position). suivant ;
i=i+1 ;
}
M. bada 8
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
(*e).suivant = (*position).suivant ;
(*position).suivant = e ;
2
Position
E1 E2 E3 E4 E5 NULL
Tête
4 3
Remarque : attention d’inverser les étapes 3 et 4, car ceci mène a perdre la 2eme partie de la liste
Il est nécessaire de déclarer un pointeur local (P1) qui va pointer sur l'élément à supprimer, et permettre de libérer
l'espace qu'il occupait.
P1
E1 E2 E3 E4 E5 NULL
Liste Etudiant* P1 ;
P1= liste ;
Liste = (*liste).suivant ;
Free (P1) ;
M. bada 9
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
P2 P1
E1 E2 E3 E4 E5 NULL
Tête
P1= liste ;
P2= liste ;
}
// A la fin de cette boucle P1 est toujours avancé d’un pas par rapport a P2.
(*P2).suivant = NULL ;
P2 P1
E1 E2 E3 E4 E5 NULL
Tête
M. bada 10
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
I=0 ;
while ( i < K-1 )
{
P2=P1 ; // sauvegarder l’ancienne valeur de P1
P1= (*P1).suivant ; // avancer P1 seulement
i = i+1 ;
}
// A la fin de cette boucle : P2 pointe vers l’élément précèdent
// A la fin de cette boucle : P1 pointe vers l’élément suivant
(*P2).suivant = (*P1).suivant;
Ex : si on veut introduire les 3 étudiants dont les prénoms sont : « Atef» puis « Hacene » puis « Seif»
Le résultat est : [seif, hacene, atef]
On remarque que le dernier élément saisi est le premier élément de la liste : (Last In First Out).
do {
//allocation d’espace mémoire pour le nouvel élément
E= (etudiant*) malloc(sizeof(etudiant)) ;
//lire le N et le Nom
scanf ("%i",&(*E).N);
scanf ("%s",&(*E).nom);
//poser la question a l’utilisateur : est ce que vous voulez insérer un autre élément ?
//bol=0 # non , bol = 1 # oui
scanf ("%i",&bol);
M. bada 11
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
Ex : si on veut introduire les 3 étudiants dont les prénoms sont : « Atef» puis « Hacene » puis « Seif»
Le résultat est : [atef, hacene, seif]
On remarque que le premier élément saisi est le premier élément de la liste : (First In First Out).
Etape 0 : initialisation
Tête = derElement
NULL = NULL
Etape 1 : boucle # i =1 # Tete= NULL (cette étape s’exécute une seule fois)
derElement
E1 NULL
1:
Création
Tête 2 d’élément
derElement =
derElement = @ E1 (*derElement).suivant ;
=@ E2
5
E1 @E2 E2 NULL
4
1:
Création
Tête
d’élément
M. bada 12
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
derElement =
derElement = @ E2 (*derElement).suivant ;
=@ E3
5
E1 @E2 E2 @E3 E3 NULL
4
1:
Création
Tête d’élément
si (tete == NULL){
// Ce bloc sera exécuté une seule fois (le 1 er élément)
tete = E ; 2+3
derElement= Tete ;
}else{
// A partir du 2eme élément
(*derElement).suivant = E ;
4+5
derElement=(*derElement).suivant ;
}
M. bada 13
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
5. Types de listes :
5.1. Liste chaînée simple constituée d'éléments reliés entre eux par des pointeurs (suivant).
5.2. Liste chaînée ordonnée : c’est une liste simplement chainée où l'élément suivant est plus grand que le précédent.
L'insertion et la suppression d'élément se font de façon à ce que la liste reste triée.
5.3. Liste doublement chaînée : c’est une liste où chaque élément dispose non plus d'un seul pointeur mais de deux
pointeurs pointant respectivement sur l'élément précédent et l'élément suivant. Ceci permet de lire la liste dans les
deux sens, du premier vers le dernier élément ou inversement.
struct element
{
element* Precedent ;
type1 Champ_1;
....
typeN Champ_N;
element* Suivant ;
}
Le pointeur Précèdent du premier élément ainsi que le pointeur Suivant du dernier élément
contiennent la valeur Nil.
M. bada 14
Chapitre 3 : les listes Université de Batna 2 Algorithmique et structures de données
5.4. Liste circulaire : c’est une liste où le dernier élément pointe sur le premier élément de la liste.
5.5. Liste doublement chainée circulaire : il s'agit d'une liste doublement chaînée où : le dernier élément pointe le
1er élément et le premier élément pointe également sur le dernier.
Remarque : Ces différents types peuvent être mixés selon les besoins.
6. Inconvénients :
L’inconvénient des listes chainées réside dans l’accès séquentiel à leurs éléments.
En effet, pour accéder à un élément, il faut passer par tous les éléments qui le précèdent # augmentation du temps de calcul.
Afin de pallier ce problème, une autre structure de donnée peut etre utilisée, il s’agit de la structure ARBRE (voir chapitre 5).
M. bada 15