Une liste est une structure qui permet de stocker de manière ordonnée des éléments. Une liste est composée de maillons, un maillon étant une structure qui contient un élément à stocker et un pointeur (au sens large) sur le prochain maillon de la liste.
On parle de pointeur au sens large car il y a principalement deux manières de représenter une liste chaînée, ce qui entraîne deux types de pointeur qui sont précisés par la suite.
Une première façon de modéliser une liste chaînée consiste à allouer à l'avance un certain nombre de maillons. Autrement dit, un tableau de maillons, de taille fixée, est alloué à la création de la liste. Par la suite, la liste est formée en utilisant comme maillons des cases de ce tableau. Avec cette modélisation, un pointeur sur un prochain maillon dans la liste sera tout simplement un indice dans le tableau.
Par convention, un pointeur sur rien aura la valeur VIDE = -1. La figure suivante représente une liste chaînée par cette modélisation. La liste contient les chaînes de caractères suivantes classées dans cet ordre: "Paris", "Marseille", "Bordeaux", "Lyon", "Toulouse". Voici la structure de données correspondant à une liste chaînée représentée par tableau.
NMAX est une constante représentant la taille du tableau alloué. n est le nombre d'éléments dans la liste. tete et fin pointent respectivement sur la tête (premier élément) et la queue (dernier élément) de la liste.
Une seconde façon de modéliser une liste chaînée consiste à allouer dynamiquement les maillons chaque fois que cela est nécessaire. Dans ce cas, un pointeur sur un maillon sera bien ce que l'on appelle couramment un pointeur, c'est-à-dire un pointeur sur la mémoire centrale de l'ordinateur.
Un pointeur sur rien aura donc la valeur VIDE = NIL. La figure suivante représente une liste chaînée par cette modélisation. Elle reprend la même liste que pour l'exemple de modélisation par tableau. Voici la structure de données correspondant à une liste chaînée représentée par pointeurs.
Comme pour la représentation par tableau, tete et fin pointent respectivement sur la tête et la queue de la liste.
A partir de maintenant, nous allons employer le type LISTE qui représente une liste chaînée au sens général, c'est-à-dire sans se soucier de sa modélisation. LISTE représente aussi bien une liste par tableau (LISTE_TAB) qu'une liste par pointeurs (LISTE_PTR). La présentation des opérations appliquées sur une liste chaînée est divisée en deux parties. Tout d'abord, on présente quelques opérations de base dont l'implémentation (le contenu) est propre à chacune des modélisations.
Néanmoins, quelle que soit la modélisation choisie pour la liste chaînée, ces opérations ont les mêmes prototypes (mêmes paramètres et type de retour), ce qui permet par la suite d'écrire des opérations générales indépendantes de la modélisation choisie.
Cette fonction initialise les valeurs de la structure représentant la liste pointée par l pour que celle-ci soit vide. Dans le cas d'une représentation par tableau, une liste est vide lorsque tete et fin pointent sur VIDE. Dans ce cas, il faut également que n soit nul.
Comme nous l'avons précisé précédemment, CONTENU n'est pas une fonction mais un mot-clé qui remplace littéralement un jeu d'instructions. Cette opération retourne donc le contenu d'un pointeur p sur un maillon d'une liste l. Dans le cas d'une représentation par tableau, il s'agit de retourner le maillon d'indice p du tableau représentant la liste l.
Cette fonction réserve l'espace mémoire nécessaire pour un
nouveau maillon dans la liste pointée par l et retourne un pointeur sur ce
maillon. Dans le cas d'une représentation par tableau, on prendra comme nouveau maillon un
maillon non utilisé dans le tableau l
Cette fonction libère l'espace occupé par un maillon à
l'adresse p dans une liste pointée par l. Dans le cas d'une
représentation par tableau, on supprimera un maillon en décalant d'une case vers la
gauche tous les maillons dont l'indice est supérieur à p dans
l
Cette fonction initialise les valeurs de la structure représentant la liste pointée par l pour que celle-ci soit vide. Dans le cas d'une représentation par pointeurs, une liste est vide lorsque tete et fin pointent sur VIDE.
Comme nous l'avons précisé précédemment, CONTENU n'est pas une fonction mais un mot-clé qui remplace littéralement un jeu d'instructions. Cette opération retourne donc le contenu d'un pointeur p sur un maillon d'une liste l. Dans le cas d'une représentation par pointeurs, il s'agit de retourner le maillon pointé directement par p.
Cette fonction réserve l'espace mémoire nécessaire pour un nouveau maillon dans la liste pointée par l et retourne un pointeur sur ce maillon. Dans le cas d'une représentation par pointeurs, l'espace nécessaire est alloué en mémoire centrale.
Cette fonction libère l'espace occupé par un maillon à l'adresse p dans une liste pointée par l. Dans le cas d'une représentation par pointeurs, il suffit de libérer l'espace alloué dans la mémoire centrale.
Cette fonction indique si la liste l est vide. Une liste est vide si la tête pointe sur VIDE.
Cette fonction alloue un nouveau maillon pour la liste pointée par l et place un élément e à l'intérieur. Si un maillon a pu être alloué, son adresse est retournée. Sinon, la valeur VIDE est renvoyée.
Cette fonction recherche un maillon dans la liste l. Le critère de recherche est défini par le mot-clé TROUVE(e) qui retourne VRAI si l'élément e correspond au critère de recherche. Une fois l'élément trouvé, l'adresse du maillon qui le précède est stockée à l'adresse p. Dans le cas où le maillon trouvé est le premier de la liste, alors VIDE est stockée à l'adresse p. La fonction renvoie VRAI si elle a trouvé un élément correspondant au critère de recherche.
Cette fonction insère, dans la liste pointée par l, le maillon pointé par p2 juste après le maillon pointé par p1. Si p1 = VIDE, alors l'insertion se fait en tête de la liste. Les liens de chaînage sont modifiés pour intégrer le nouveau maillon. On prend garde de mettre à jour également le pointeur sur la queue de la liste.
Cette fonction supprime, dans la liste pointée par l, le maillon suivant celui pointé par p. Si p = VIDE, alors c'est l'élément de tête qui est supprimé. Les liens de chaînage sont modifiés et l'espace mémoire occupé par le maillon est libéré. On prend garde de mettre à jour le pointeur sur la queue de la liste.
Cette fonction insère l'élément e en tête de la liste pointée par l. Si l'opération réussit (i.e. il reste de la mémoire pour créer un maillon) alors la valeur VRAI est renvoyée.
Cette fonction insère l'élément e en queue de la liste pointée par l. Si l'opération réussit (i.e. il reste de la mémoire pour créer un maillon) alors la valeur VRAI est renvoyée.
Cette fonction supprime le maillon en tête de la liste pointée par l. Si la liste n'est pas déjà vide, la valeur VRAI est renvoyée.
Cette fonction retourne le maillon en tête de la liste l. A n'utiliser que si la liste l n'est pas vide.
Cette fonction retourne le maillon en queue de la liste l. A n'utiliser que si la liste l n'est pas vide.
La représentation par tableau d'une liste chaînée n'a finalement que peu d'intérêt par rapport à un tableau, si ce n'est au niveau de l'insertion. En effet, pour insérer un élément à n'importe quelle position dans une liste chaînée par tableau, il suffit d'ajouter un élément à la fin du tableau et de faire les liens de chaînage. Alors que dans un tableau, l'insertion d'un élément implique le décalage vers la droite d'un certain nombre d'éléments. Cependant au niveau de la suppression, la liste chaînée par tableau a le même défaut qu'un tableau: il faut décaler un certain nombres d'éléments vers la gauche. Dans le cas d'une liste chaînée par pointeurs, le défaut constaté au niveau de la suppression d'un élément disparaît. En résumé, une liste chaînée par pointeurs permet une insertion et une suppression rapide des éléments. Cependant, contrairement au tableau, une liste chaînée interdit un accès direct aux éléments (mis à part la tête et la queue).
|