Ch09 - Les Listes Simplement Chain-Es
Ch09 - Les Listes Simplement Chain-Es
Ch09 - Les Listes Simplement Chain-Es
SCIENCES DE SFAX
Année Universitaire : 2023-2024
1. Introduction
Il est possible de créer un conteneur (variable) de plusieurs valeurs de mêmes types soit par :
• Listes chainées: les éléments sont répartis dans différentes zones mémoire et reliés entre eux
par des pointeurs.
Dans ce cas les éléments peuvent être de n'importe quel type d'éléments : entiers, caractères,
structures, tableaux, voir même d'autres listes chaînées.
• l'adresse de l'élément suivant, s'il existe. S'il n'y a plus d'élément suivant, alors l'adresse
suivante sera la constante NULL, et désignera la fin de la chaîne.
1
Exemple :
struct element
{
int valeur;
struct element *suivant;
};
void parcours(liste l)
{
/*on utilise un pointeur temporaire tmp qu’on pointe à l’état
sur le premier élément de la liste qui est pointé par l*/
element* tmp=l;
if(tmp->suivant!= NULL)
{
/* tant que l’élément suivant existe, on pointe tmp vers
celui-ci*/
tmp = tmp->suivant;
}
}
2
4. Ajouter un élément en tête de liste
Lors d'un ajout en tête, nous allons créer un élément, lui assigner la valeur que l'on veut
ajouter, puis pour terminer, raccorder cet élément à la liste passée en paramètre.
• Il faut créer un pointeur temporaire tmp pour parcourir les éléments de la liste l.
• Un élément sera forcément le dernier de la liste si son champ suivant est pointé vers la
constante symbolique NULL .
3
liste AjouterFin(liste l, int x)
{
/*On crée un nouvel élément*/
element* nouveau = (element*)malloc(sizeof(element));
/*On assigne la valeur au nouvel élément*/
nouveau->valeur = x;
/*On ajoute en fin, donc aucun élément ne va suivre*/
nouveau->suivant = NULL;
if(l == NULL)
{
/*Si la liste est vidée il suffit de renvoyer l'élément créé*/
return nouveau;
} else
{
/*Sinon, on parcourt la liste à l'aide d'un pointeur temporaire et on
indique que le dernier élément de la liste est relié au nouvel
élément*/
element* tmp=l;
while(tmp->suivant != NULL)
{
tmp = tmp->suivant;
}
tmp->suivant = nouveau;
return l;
}
}
4
6. Supprimer un élément en tête de la liste
Si la liste n'est pas vide, on stocke l'adresse du deuxième élément, on supprime le premier
élément, et on renvoie la nouvelle liste.
• Il ne faut pas utiliser la fonction free pour libérer le premier élément avant d'avoir stocké
l'adresse du second, si non il sera impossible de la récupérer.
liste SupprimerTete(liste l)
{
/*Si la liste est non vide, on se prépare à renvoyer
l'adresse de l'élément en 2ème position */
if(l != NULL)
{
element* tmp = l->suivant;
/* On libère le premier élément */
free(l);
/* On retourne le nouveau début de la liste */
return tmp;
}else
{
return NULL;
}
}
5
• Si la liste contient un seul élément, on le libère et on retourne NULL
• Si la liste contient au moins deux éléments alors on utilise deux pointeurs, un pointeur tmp
qui pointe sur l'élément courant et un autre ptmp qui pointe sur l'élément précédent tant qu'on
n'est pas au dernier élément, on déplace ces pointeurs d'une position.
• A la sortie de la boucle , tmp pointe sur le dernier élément, et ptmp sur l'avant-dernier. On
lie , ptmp à NULL et on libère tmp. L'avant-dernier se place alors à la fin et on retourne la
nouvelle liste l qui pointe toujours sur le premier élément.
Il faut parcourir la liste jusqu'à son dernier élément, indiquer que l'avant dernier élément va
devenir le dernier de la liste et libérer le dernier élément pour enfin retourner le pointeur sur le
premier élément de la liste d'origine.
liste SupprimerFin(liste l)
{
/* Si la liste est vide, on retourne NULL */
if(l == NULL)
return NULL;
/* Si la liste contient un seul élément */
if(l->suivant == NULL)
{
/*On le libère et on retourne NULL (la liste est maintenant vide)*/
free(l);
return NULL;
}
/* Si la liste contient au moins deux éléments */
element* tmp = l;
element* ptmp = NULL;
6
/* Tant qu'on n'est pas au dernier élément */
while(tmp->suivant != NULL)
{
/* ptmp stock l'adresse de tmp */
ptmp = tmp;
/* On déplace tmp (mais ptmp garde l'ancienne valeur de tmp */
tmp = tmp->suivant;
}
/* A la sortie de la boucle, tmp pointe sur le dernier élément, et
ptmp sur l'avant-dernier. On pointe l'avant-dernier élément vers NULL
et on supprime le dernier élément */
ptmp->suivant = NULL;
free(tmp);
return l;
}
8. Recherche d'un élément dans la liste
• Le but est de renvoyer l'adresse du premier élément trouvé ayant une certaine valeur. Si
aucun élément n'est trouvé, on renverra NULL.
• L'intérêt est de pouvoir, une fois le premier élément trouvé, chercher la prochaine
occurrence en recherchant à partir de l'élément qui suit l'élément recherché. On parcourt donc
la liste jusqu'au bout, et dès qu'on trouve un élément qui correspond à ce que l'on recherche,
on renvoie son adresse.
7
return tmp;
tmp = tmp -> suivant;
}
return NULL;
}
• Il est aussi possible d'écrire cette fonction en parcourant l'ensemble de la liste avec un
compteur que l'on incrémente à chaque fois que l'on passe sur un élément ayant la valeur
recherchée.
8
10.Recherche du i-ème élément
Il suffit de se déplacer i fois à l'aide du pointeur temporaire tmp le long de la liste chaînée et
de renvoyer l'élément à l'indice i. Si la liste contient moins de i élément(s), alors nous
renverrons NULL.
• Sinon, il y a un élément (celui que l'on est en train de traiter)plus le nombre d'éléments
contenus dans le reste de la liste.
9
int NombreElements(liste l)
{
/* Si la liste est vide, il y a 0 élément */
if(l == NULL)
return 0;
/*Sinon, il y a un élément (celui que l'on est en train de traiter)
plus le nombre d'éléments contenus dans le reste de la liste*/
return 1+ NombreElements(l->suivant);
}
10
/* Si l'élément en cours de traitement ne doit pas être supprimé,
alors la liste finale commencera par cet élément et suivra une liste
ne contenant plus d'élément ayant la valeur recherchée*/
l->suivant = SupprimerElement(l->suivant, x);
return l;
}
}
Conclusion
Les listes sont des structures de données informatiques qui permettent, au même titre que les
tableaux, de garder en mémoire des données en respectant un certain ordre : on peut ajouter,
enlever ou consulter un élément en début ou en fin de liste, ...
Les listes chaînées, par rapport aux tableaux, possèdent les avantages suivants :
• Elles sont dynamiques et n’occupent qu’un minimum d’espace lorsqu’il n’y a pas
d’élément à l’intérieur,
• L’ajout ou le retrait d’une donnée dans une liste ordonnée ne nécessite pas le
déplacement des autres données de la liste,
• L’ajout d’une donnée ne demande qu’une réservation minimal de mémoire (la taille
d’une donnée et celle d’un ou deux pointeur(s)), alors que pour un tableau dynamique
il faut pouvoir alloué un bloc important de mémoire.
• Le code nécessaire pour les gérer est plus complexe que celui pour gérer des tableaux
dynamiques,
• Elles occupent plus d’espaces qu’un tableau dynamique pour une même quantité de
donnée (à cause des pointeurs),
• Elles ne permettent pas d’accéder directement à un élément, ce qui empêche entre autres
la recherche dichotomique.
11