Cours N°10 : STRUCTURES DE DONNEES
COMPLEXES: LES LISTES LINEAIRES CHAINÉES (LLC)
1ere année – cycle préparatoire, Ecole Supérieure des Sciences
Appliquées d’Alger (ESSA-Alger)
2021-2022
2
Motivation
 La déclaration d’un tableau signifie la réservation d’un espace
mémoire contiguë suffisant pour tous les éléments du tableau, donc
il faut connaître sa taille au préalable
 Les tableaux se révèlent parfois assez limités. Par exemple, si un
tableau possède une taille donnée et que nous souhaitons plus tard
dans notre programme que nous avons besoin de plus d'espace, il
sera impossible d'agrandir ce tableau. De plus, il n'est pas possible
d'insérer une case au milieu du tableau ou de la supprimer sans
toucher aux cases précédentes/suivantes. Ainsi, il est possible de
déclarer un tableau de grande taille et nous constatons par la suite
que nous n’avons besoin que de quelques cases
 Tout ça peut être couteux en termes du temps et d’espace
3
Définition
 Les listes chaînées représentent une façon d'organiser les données
en mémoire de manière beaucoup plus flexible. Comme à la base le
langage C ne propose pas ce système de stockage, nous allons
devoir le créer nous-mêmes de toutes pièces
 Les éléments de notre liste sont répartis dans la mémoire et reliés
entre eux par des pointeurs (chaque élément possède l'adresse de
l'élément suivant). On peut ajouter et enlever des éléments d'une
liste chaînée à n'importe quel endroit, à n'importe quel instant, sans
devoir recréer la liste entière
4
Tableaux Vs LLCs
Tableau LLC
Déclaration Lorsqu'on déclare un tableau, la
variable contiendra l'adresse du
premier élément de notre
tableau
Il suffit de créer le pointeur qui va pointer sur
le premier élément de notre liste chaînée
Taille La taille est connue La taille est inconnue au départ, la liste peut
avoir autant d'éléments que la mémoire le
permet
Accès Comme le stockage est contigu,
et la taille de chacun des
éléments est connue, il est
possible d'atteindre
directement la case i d'un
tableau
Il est impossible d'accéder directement à
l'élément i de la liste chainée. Pour ce faire, il
nous faudra parcourir les i-1 éléments
précédents de la liste
Manipulati
on
Pour supprimer ou ajouter un
élément à un tableau, il faut
créer un nouveau tableau et
supprimer l'ancien
Il est possible d'ajouter, de supprimer,
d'intervertir des éléments d'une liste chaînée
sans avoir à recréer la liste en entier, mais en
manipulant simplement leurs pointeurs
5
Un maillon: déclaration
Typiquement un élément d'une liste chainée, appelé aussi un
maillon, est défini par une structure. Cette structure contient
les informations en relation avec les objectifs de l'application
(la valeur qu'on veut stocker ) et un pointeur sur une structure
de même type (l'adresse de l'élément suivant, s'il existe. S'il n'y
a plus d'élément suivant, alors l'adresse sera NULL, et
désignera le bout de la chaîne )
6
Une liste: déclaration
 Deux positions sont très importantes dans une liste chainée : le début et la fin, souvent
désignées par "premier et dernier" ou "tête et queue". Sans le premier impossible de savoir
où commence la chaine et sans le dernier impossible de savoir où elle s'arrête
 Le début est donné par l'adresse du premier maillon. En général une chaine prend ainsi le
nom du premier maillon :
 Lorsque la liste est vide le premier maillon prend la valeur NULL. Ensuite, quelque part dans
le programme, en fonction d'une action de l'utilisateur, de la mémoire va être allouée à ce
premier maillon et des valeurs vont être données aux champs de la structure du maillon,
c'est à dire qu'il va être initialisé, par exemple :
 Le champ suiv prend obligatoirement une valeur : soit la valeur de l'élément suivant, soit,
s'il n'y en a pas, la valeur de fin de chaine. Par défaut, dans la cas d'un maillon seul non
inséré dans une chaine, il prendra la valeur NULL parce qu'elle est facilement repérable par
la suite dans le programme.
7
Une liste: déclaration
Remarque: Il est important de toujours initialiser la liste chaînée à NULL. Le cas échéant, elle
sera considérée comme contenant au moins un élément. De manière générale, il est plus sage
de toujours initialiser nos pointeurs
8
Manipulation des LLCs
Les actions sont en général toujours les mêmes et toutes ne sont pas
toujours nécessaires, en gros il s'agit d'écrire des fonctions pour :
 Liste vide : savoir si une liste est vide ou pas.
 Ajouter un maillon : ajouter un maillon à la liste, soit au début, soit à la
fin.
 Parcourir : passer chaque élément en revue dans l'ordre du début vers
la fin
 Extraire : récupérer les données d'un maillon et l'enlever de la chaine
 Supprimer : enlever un maillon de la liste sans récupérer ses données
 Insérer : ajouter un maillon quelque part dans la chaine
 Détruire une liste : désallouer tous les maillons de la liste
 Copier une liste : cloner de la chaine
9
Manipulation des LLCs: Liste vide
Nous considérons la structure suivante:
Nous utilisons comme fin de liste la valeur NULL. Si donc liste est NULL
c'est que la liste est vide. Eventuellement nous pouvons avoir une petite
fonction qui retourne 1 ou 0 selon que la liste est vide ou pas :
10
Manipulation des LLCs: Initialiser un élément
Il est indispensable d'allouer la mémoire pour chaque nouvel élément de la
liste. Le mieux est de le faire au moment de l'initialisation des datas, dans la
fonction d'initialisation, lorsque les champs de l'élément prennent des valeurs.
Pour les tests ici le champ val prend la valeur val. Par précaution le pointeur suiv
est initialisé à NULL. En effet la manipulation des pointeurs est délicate. Pour
éviter des bugs il est recommandé de toujours mettre à NULL un pointeur non
alloué. A la fin, la fonction retourne l'adresse du nouvel élément alloué et
initialisé :
11
Manipulation des LLCs: Ajouter un élément au début
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. Lors d'un ajout en tête, on devra donc assigner à suiv l'adresse du
premier élément de la liste passé en paramètre
l
l
Manipulation des LLCs: Ajouter un élément à la fin
Cette fois-ci, c'est un peu plus compliqué. Il nous faut tout d'abord créer
un nouvel élément, lui assigner sa valeur, et mettre l'adresse de
l'élément suivant à NULL. En effet, comme cet élément va terminer la
liste nous devons signaler qu'il n'y a plus d'élément suivant. Ensuite, il
faut faire pointer le dernier élément de liste originale sur le nouvel
élément que nous venons de créer. Pour ce faire, il faut créer un
pointeur temporaire sur element qui va se déplacer d'élément en
élément, et voir si cet élément est le dernier de la liste. Un élément sera
forcément le dernier de la liste si NULL est assigné à son champ suiv.
Manipulation des LLCs: Ajouter un élément à la fin
Manipulation des LLCs: Parcourir une liste ou l’afficher
Pour parcourir une liste chainée, il suffit avec un pointeur de
prendre successivement l'adresse de chaque maillon suivant. Au
départ le pointeur prend l'adresse du premier élément qui est
l'adresse de la liste, ensuite il prend l'adresse du suivant et ainsi de
suite :
Pour chaque élément il est possible d'accéder aux datas de
l'élément.
Manipulation des LLCs: Parcourir une liste ou l’afficher
Manipulation des LLCs: Rechercher un élément dans
la liste
Pour rechercher une valeur donnée « valeur », il faut parcourir la
liste chainée jusqu’à ce qu’on trouve cette valeur ou parcourir
toute la liste, il suffit avec un pointeur de prendre successivement
l'adresse de chaque maillon suivant. Au départ le pointeur prend
l'adresse du premier élément qui est l'adresse de la liste. La
fonction retourne l’adresse du maillon contenant cette valeur ou
NULL si cette valeur n’existe pas.
Manipulation des LLCs: Rechercher un élément dans
la liste
Remarque:
Il se peut que la fonction renvoie 1 ou 0 pour dire si la valeur existe
ou pas ou la position de cette valeur.
Manipulation des LLCs: Insérer un élément dans la
liste
Le fait d'insérer plutôt qu'ajouter un élément dans la liste suppose
un classement. Il faut un critère d'insertion? Par exemple nous
allons insérer nos éléments de façon à ce que les valeurs entières
soient classées en ordre croissant. Trois cas sont possibles : la liste
est vide, insérer au début avant le premier, chercher la place
précédente et insérer après. Dans ce dernier cas, le maillon est à
insérer quelque part dans la liste. Pour ce faire il faut chercher la
bonne place et conserver l'adresse du maillon qui précède.
Pour trouver le maillon précédent la liste est parcourue tant que
l'élément courant n'est pas NULL et que la valeur de l'élément à
insérer est supérieure à la valeur de l'élément courant. Nous avons
besoin de deux pointeurs : un pour l'élément courant et un pour
l'élément précédent. A chaque tour, avant d'avancer l'élément
courant de un maillon, l'adresse de l'élément précédent est
sauvegardée
Manipulation des LLCs: Insérer un élément dans la
liste
Manipulation des LLCs: Supprimer un élément de la
liste (au début de la liste)
La suppression du premier élément suppose de bien actualiser la
valeur du pointeur qui indique toujours le début de la liste.
Manipulation des LLCs: Supprimer un élément de la
liste (à la fin de la liste)
La suppression à la fin suppose de se positionner sur l'avant dernier maillon puis de
supprimer le suivant et de mettre suivant à NULL. Il faut que la liste ne soit pas vide et traiter
le cas ou il n'y a qu'un seul maillon dans la liste, le premier.
Manipulation des LLCs: Supprimer un élément de la
liste correspondant à un critère
L'objectif cette fois est de supprimer un maillon quelconque de la
liste en fonction d'un critère donné. Le critère ici est que le champ
val de l'élément soit égal à une valeur donnée. La recherche
s'arrête si un élément répond au critère et nous supprimons
uniquement le premier élément trouvé s'il y en a un. Comme pour
les suppressions précédentes la liste ne doit pas être vide. Il faut
prendre en compte le cas où l'élément à supprimer est le premier
de la liste et pour tous les autre éléments il faut disposer de
l'élément qui précède celui à supprimer afin de pouvoir
reconstruire la chaine
Manipulation des LLCs: Supprimer un élément de la
liste correspondant à un critère
Manipulation des LLCs: Détruire une liste (supprimer
tout ses éléments)
Manipulation des LLCs: Copier une liste (la cloner)
Copier une liste suppose de parcourir la liste à copier et de construire en
parallèle une autre liste. Pour chaque élément de la liste à copier il faut
allouer un élément pour la copie et relier les éléments de la copie entre eux.
Il faut également veiller à conserver l'adresse du début de la copie

Structure des données complexes . pptx .

  • 1.
    Cours N°10 :STRUCTURES DE DONNEES COMPLEXES: LES LISTES LINEAIRES CHAINÉES (LLC) 1ere année – cycle préparatoire, Ecole Supérieure des Sciences Appliquées d’Alger (ESSA-Alger) 2021-2022
  • 2.
    2 Motivation  La déclarationd’un tableau signifie la réservation d’un espace mémoire contiguë suffisant pour tous les éléments du tableau, donc il faut connaître sa taille au préalable  Les tableaux se révèlent parfois assez limités. Par exemple, si un tableau possède une taille donnée et que nous souhaitons plus tard dans notre programme que nous avons besoin de plus d'espace, il sera impossible d'agrandir ce tableau. De plus, il n'est pas possible d'insérer une case au milieu du tableau ou de la supprimer sans toucher aux cases précédentes/suivantes. Ainsi, il est possible de déclarer un tableau de grande taille et nous constatons par la suite que nous n’avons besoin que de quelques cases  Tout ça peut être couteux en termes du temps et d’espace
  • 3.
    3 Définition  Les listeschaînées représentent une façon d'organiser les données en mémoire de manière beaucoup plus flexible. Comme à la base le langage C ne propose pas ce système de stockage, nous allons devoir le créer nous-mêmes de toutes pièces  Les éléments de notre liste sont répartis dans la mémoire et reliés entre eux par des pointeurs (chaque élément possède l'adresse de l'élément suivant). On peut ajouter et enlever des éléments d'une liste chaînée à n'importe quel endroit, à n'importe quel instant, sans devoir recréer la liste entière
  • 4.
    4 Tableaux Vs LLCs TableauLLC Déclaration Lorsqu'on déclare un tableau, la variable contiendra l'adresse du premier élément de notre tableau Il suffit de créer le pointeur qui va pointer sur le premier élément de notre liste chaînée Taille La taille est connue La taille est inconnue au départ, la liste peut avoir autant d'éléments que la mémoire le permet Accès Comme le stockage est contigu, et la taille de chacun des éléments est connue, il est possible d'atteindre directement la case i d'un tableau Il est impossible d'accéder directement à l'élément i de la liste chainée. Pour ce faire, il nous faudra parcourir les i-1 éléments précédents de la liste Manipulati on Pour supprimer ou ajouter un élément à un tableau, il faut créer un nouveau tableau et supprimer l'ancien Il est possible d'ajouter, de supprimer, d'intervertir des éléments d'une liste chaînée sans avoir à recréer la liste en entier, mais en manipulant simplement leurs pointeurs
  • 5.
    5 Un maillon: déclaration Typiquementun élément d'une liste chainée, appelé aussi un maillon, est défini par une structure. Cette structure contient les informations en relation avec les objectifs de l'application (la valeur qu'on veut stocker ) et un pointeur sur une structure de même type (l'adresse de l'élément suivant, s'il existe. S'il n'y a plus d'élément suivant, alors l'adresse sera NULL, et désignera le bout de la chaîne )
  • 6.
    6 Une liste: déclaration Deux positions sont très importantes dans une liste chainée : le début et la fin, souvent désignées par "premier et dernier" ou "tête et queue". Sans le premier impossible de savoir où commence la chaine et sans le dernier impossible de savoir où elle s'arrête  Le début est donné par l'adresse du premier maillon. En général une chaine prend ainsi le nom du premier maillon :  Lorsque la liste est vide le premier maillon prend la valeur NULL. Ensuite, quelque part dans le programme, en fonction d'une action de l'utilisateur, de la mémoire va être allouée à ce premier maillon et des valeurs vont être données aux champs de la structure du maillon, c'est à dire qu'il va être initialisé, par exemple :  Le champ suiv prend obligatoirement une valeur : soit la valeur de l'élément suivant, soit, s'il n'y en a pas, la valeur de fin de chaine. Par défaut, dans la cas d'un maillon seul non inséré dans une chaine, il prendra la valeur NULL parce qu'elle est facilement repérable par la suite dans le programme.
  • 7.
    7 Une liste: déclaration Remarque:Il est important de toujours initialiser la liste chaînée à NULL. Le cas échéant, elle sera considérée comme contenant au moins un élément. De manière générale, il est plus sage de toujours initialiser nos pointeurs
  • 8.
    8 Manipulation des LLCs Lesactions sont en général toujours les mêmes et toutes ne sont pas toujours nécessaires, en gros il s'agit d'écrire des fonctions pour :  Liste vide : savoir si une liste est vide ou pas.  Ajouter un maillon : ajouter un maillon à la liste, soit au début, soit à la fin.  Parcourir : passer chaque élément en revue dans l'ordre du début vers la fin  Extraire : récupérer les données d'un maillon et l'enlever de la chaine  Supprimer : enlever un maillon de la liste sans récupérer ses données  Insérer : ajouter un maillon quelque part dans la chaine  Détruire une liste : désallouer tous les maillons de la liste  Copier une liste : cloner de la chaine
  • 9.
    9 Manipulation des LLCs:Liste vide Nous considérons la structure suivante: Nous utilisons comme fin de liste la valeur NULL. Si donc liste est NULL c'est que la liste est vide. Eventuellement nous pouvons avoir une petite fonction qui retourne 1 ou 0 selon que la liste est vide ou pas :
  • 10.
    10 Manipulation des LLCs:Initialiser un élément Il est indispensable d'allouer la mémoire pour chaque nouvel élément de la liste. Le mieux est de le faire au moment de l'initialisation des datas, dans la fonction d'initialisation, lorsque les champs de l'élément prennent des valeurs. Pour les tests ici le champ val prend la valeur val. Par précaution le pointeur suiv est initialisé à NULL. En effet la manipulation des pointeurs est délicate. Pour éviter des bugs il est recommandé de toujours mettre à NULL un pointeur non alloué. A la fin, la fonction retourne l'adresse du nouvel élément alloué et initialisé :
  • 11.
    11 Manipulation des LLCs:Ajouter un élément au début 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. Lors d'un ajout en tête, on devra donc assigner à suiv l'adresse du premier élément de la liste passé en paramètre l l
  • 12.
    Manipulation des LLCs:Ajouter un élément à la fin Cette fois-ci, c'est un peu plus compliqué. Il nous faut tout d'abord créer un nouvel élément, lui assigner sa valeur, et mettre l'adresse de l'élément suivant à NULL. En effet, comme cet élément va terminer la liste nous devons signaler qu'il n'y a plus d'élément suivant. Ensuite, il faut faire pointer le dernier élément de liste originale sur le nouvel élément que nous venons de créer. Pour ce faire, il faut créer un pointeur temporaire sur element qui va se déplacer d'élément en élément, et voir si cet élément est le dernier de la liste. Un élément sera forcément le dernier de la liste si NULL est assigné à son champ suiv.
  • 13.
    Manipulation des LLCs:Ajouter un élément à la fin
  • 14.
    Manipulation des LLCs:Parcourir une liste ou l’afficher Pour parcourir une liste chainée, il suffit avec un pointeur de prendre successivement l'adresse de chaque maillon suivant. Au départ le pointeur prend l'adresse du premier élément qui est l'adresse de la liste, ensuite il prend l'adresse du suivant et ainsi de suite : Pour chaque élément il est possible d'accéder aux datas de l'élément.
  • 15.
    Manipulation des LLCs:Parcourir une liste ou l’afficher
  • 16.
    Manipulation des LLCs:Rechercher un élément dans la liste Pour rechercher une valeur donnée « valeur », il faut parcourir la liste chainée jusqu’à ce qu’on trouve cette valeur ou parcourir toute la liste, il suffit avec un pointeur de prendre successivement l'adresse de chaque maillon suivant. Au départ le pointeur prend l'adresse du premier élément qui est l'adresse de la liste. La fonction retourne l’adresse du maillon contenant cette valeur ou NULL si cette valeur n’existe pas.
  • 17.
    Manipulation des LLCs:Rechercher un élément dans la liste Remarque: Il se peut que la fonction renvoie 1 ou 0 pour dire si la valeur existe ou pas ou la position de cette valeur.
  • 18.
    Manipulation des LLCs:Insérer un élément dans la liste Le fait d'insérer plutôt qu'ajouter un élément dans la liste suppose un classement. Il faut un critère d'insertion? Par exemple nous allons insérer nos éléments de façon à ce que les valeurs entières soient classées en ordre croissant. Trois cas sont possibles : la liste est vide, insérer au début avant le premier, chercher la place précédente et insérer après. Dans ce dernier cas, le maillon est à insérer quelque part dans la liste. Pour ce faire il faut chercher la bonne place et conserver l'adresse du maillon qui précède. Pour trouver le maillon précédent la liste est parcourue tant que l'élément courant n'est pas NULL et que la valeur de l'élément à insérer est supérieure à la valeur de l'élément courant. Nous avons besoin de deux pointeurs : un pour l'élément courant et un pour l'élément précédent. A chaque tour, avant d'avancer l'élément courant de un maillon, l'adresse de l'élément précédent est sauvegardée
  • 19.
    Manipulation des LLCs:Insérer un élément dans la liste
  • 20.
    Manipulation des LLCs:Supprimer un élément de la liste (au début de la liste) La suppression du premier élément suppose de bien actualiser la valeur du pointeur qui indique toujours le début de la liste.
  • 21.
    Manipulation des LLCs:Supprimer un élément de la liste (à la fin de la liste) La suppression à la fin suppose de se positionner sur l'avant dernier maillon puis de supprimer le suivant et de mettre suivant à NULL. Il faut que la liste ne soit pas vide et traiter le cas ou il n'y a qu'un seul maillon dans la liste, le premier.
  • 22.
    Manipulation des LLCs:Supprimer un élément de la liste correspondant à un critère L'objectif cette fois est de supprimer un maillon quelconque de la liste en fonction d'un critère donné. Le critère ici est que le champ val de l'élément soit égal à une valeur donnée. La recherche s'arrête si un élément répond au critère et nous supprimons uniquement le premier élément trouvé s'il y en a un. Comme pour les suppressions précédentes la liste ne doit pas être vide. Il faut prendre en compte le cas où l'élément à supprimer est le premier de la liste et pour tous les autre éléments il faut disposer de l'élément qui précède celui à supprimer afin de pouvoir reconstruire la chaine
  • 23.
    Manipulation des LLCs:Supprimer un élément de la liste correspondant à un critère
  • 24.
    Manipulation des LLCs:Détruire une liste (supprimer tout ses éléments)
  • 25.
    Manipulation des LLCs:Copier une liste (la cloner) Copier une liste suppose de parcourir la liste à copier et de construire en parallèle une autre liste. Pour chaque élément de la liste à copier il faut allouer un élément pour la copie et relier les éléments de la copie entre eux. Il faut également veiller à conserver l'adresse du début de la copie