Numérique et sciences informatiques (spécialité) · TerminaleBac
Les listes chaînées : cours de Terminale NSI
Publié le 7 novembre 2026 · Mis à jour le 7 novembre 2026 · Signaler une erreur
L'essentiel
- Une liste chaînée est une suite de cellules ; chaque cellule contient une donnée et un lien vers une autre cellule 2.
- On ne connaît que la tête : pour atteindre un élément, on suit les liens un par un depuis le début, sans accès direct par indice.
- Ajouter ou retirer en tête ne modifie qu'un ou deux liens ; le piège est de perdre la référence vers la suite avant de l'avoir sauvegardée.
- Une liste simplement chaînée se parcourt dans un seul sens, une liste doublement chaînée dans les deux 3.
- Le parcours s'écrit avec une variable
courantqui avance tant qu'elle n'est pasNone.
Pourquoi une nouvelle structure de données ?
Tu connais déjà la liste Python : on écrit t[3] et on obtient directement le quatrième élément. Tu l'utilises sans te demander comment elle est rangée dans la mémoire de l'ordinateur. En Terminale, on change de point de vue : on construit soi-même des structures de données avec des objets, pour comprendre ce qu'elles coûtent et à quoi elles servent.
La liste chaînée est la première de ces structures. Elle te sert ensuite de modèle pour les piles, les files et les arbres, qui reposent sur la même idée : des objets qui se référencent les uns les autres.
En informatique, une liste est un type de données abstrait qui regroupe des données de façon à pouvoir y accéder librement, contrairement aux piles et aux files, dont l'accès est imposé (LIFO ou FIFO) 3. La liste sert de base à des types plus complexes comme la pile, la file ou les arbres 3.
Pour bien situer l'intérêt, comparons avec le tableau. Les données d'un tableau sont contiguës en mémoire, ce qui impose une taille fixe 3. Certains langages de haut niveau proposent des tableaux dont la taille varie, comme la liste Python : ils restent rangés d'un seul bloc en mémoire et, quand la place manque, ils sont recopiés dans une zone plus grande. À l'inverse, la taille d'une liste chaînée n'est limitée que par la mémoire disponible : pour l'agrandir, il suffit de créer une nouvelle cellule et de faire pointer vers elle une cellule déjà présente 3.
Anatomie d'une liste chaînée
Une cellule est un petit objet à deux composantes : la valeur qu'elle transporte et le lien vers la cellule suivante. Autrement dit, en plus de sa donnée, chaque élément porte une référence qui le relie à un voisin dans la liste 2.
Représentons la liste :
tête → [ 2 | • ] → [ 7 | • ] → [ 4 | • ] → [ 9 | None ]
Chaque rectangle est une cellule : à gauche la valeur, à droite le lien. La dernière cellule ne pointe vers rien : son lien vaut None. C'est ce None qui signale « la chaîne s'arrête ici ». Une liste vide, elle, est une tête qui vaut directement None.
- CréerOn crée une nouvelle cellule contenant la valeur.
- RelierSon lien suivant désigne l'ancienne tête.
- DéclarerLa tête de la liste désigne la nouvelle cellule.
Construisons à la main la liste , en commençant par la fin :
c3 = Cellule(4) # dernière cellule, suivant = None
c2 = Cellule(7, c3) # 7 pointe vers 4
c1 = Cellule(2, c2) # 2 pointe vers 7
l = Liste()
l.tete = c1
Les trois variables c1, c2, c3 ne servent qu'à construire : une fois la liste faite, seule l.tete compte. Avec l.tete.suivant.valeur, on obtient 7.
Parcourir une liste chaînée
Comme on ne connaît que la tête, on ne peut pas sauter directement au milieu. Pour voir tous les éléments, on suit les liens de cellule en cellule. C'est l'opération de base : presque tout le reste en dérive.
Voici le calcul de la longueur, méthode de la classe Liste :
def longueur(self):
n = 0
courant = self.tete
while courant is not None:
n += 1
courant = courant.suivant
return n
Sur la liste vide, courant vaut None dès le départ, la boucle ne s'exécute pas et on renvoie 0. Sur , la boucle tourne trois fois.
Pour accéder au i-ième élément (les indices commencent à 0), on avance fois :
def acces(self, i):
courant = self.tete
for _ in range(i):
if courant is None:
raise IndexError("indice trop grand")
courant = courant.suivant
if courant is None:
raise IndexError("indice trop grand")
return courant.valeur
Il faut suivre liens avant d'arriver sur la bonne cellule. Plus l'indice est grand, plus le trajet est long. C'est la grande différence avec t[i] sur un tableau, où l'on tombe directement sur la case.
Le même parcours s'écrit de façon récursive, ce qui rejoint la définition récursive de la structure : une liste est soit vide, soit une cellule suivie d'une liste. Les listes chaînées s'appuient justement sur une définition récursive, chaque élément pointant vers d'autres éléments de la liste 3.
def longueur_rec(cellule):
if cellule is None:
return 0
return 1 + longueur_rec(cellule.suivant)
Le cas de base est la chaîne vide (None), le cas récursif traite la première cellule puis la suite.
Ajouter un élément
Ajouter un élément revient à créer une cellule et à réarranger quelques liens. La difficulté n'est pas de coder, mais de choisir l'ordre des affectations.
On recommande souvent la liste chaînée quand l'ordre des éléments compte et qu'on insère ou retire des éléments n'importe où plus souvent qu'on ne les consulte 2. C'est cohérent avec ce que tu viens de voir : insérer ne coûte que quelques liens, alors qu'accéder demande de parcourir.
Supprimer un élément
Supprimer, c'est court-circuiter une cellule : on fait pointer sa précédente directement vers sa suivante. La cellule oubliée n'est plus référencée par personne, elle n'appartient plus à la liste.
Listes doublement chaînées et listes circulaires
Avec un seul lien par cellule, impossible de reculer. On peut enrichir la cellule.
La cellule possède alors trois attributs :
class CelluleD:
def __init__(self, valeur):
self.valeur = valeur
self.suivant = None
self.precedent = None
Cette souplesse a un prix. Il faut stocker un lien de plus par cellule, donc davantage de mémoire, et les mises à jour demandent plus d'instructions : insérer une cellule recopie quatre pointeurs, là où deux suffisent dans une liste simplement chaînée 2.
| Type | Liens par cellule | Parcours |
|---|---|---|
| Simplement chaînée | Un (suivant) | Un seul sens |
| Doublement chaînée | Deux (suivant, précédent) | Deux sens |
| Circulaire | Selon le type | Boucle sans début ni fin |
Liste chaînée ou liste Python ?
En Terminale, on te demande régulièrement de justifier le choix d'une structure : liste Python, dictionnaire, pile, file, arbre, graphe… et d'expliquer en quoi elle est adaptée à l'exercice 1. Voici de quoi argumenter sur les listes.
Une remarque sur Python lui-même : la liste Python (list) n'est pas une liste chaînée au sens de ce cours. Elle s'utilise avec des indices, et on distingue ses opérations, une question classique à l'épreuve pratique 1 : par exemple, tab.append(i) modifie la liste existante, alors que tab = tab + [i] construit une nouvelle liste. De même, sorted(tab) renvoie une nouvelle liste triée, tandis que tab.sort() trie tab sur place. Quand tu écris ta propre classe Liste, tu dois donc programmer explicitement ces opérations.
Un peu d'histoire pour terminer. Les listes chaînées ont été conçues en 1955-1956 par Allen Newell, Cliff Shaw et Herbert Simon, de RAND Corporation 2. Elles formaient la structure de base de leur langage IPL, utilisé pour développer des programmes d'intelligence artificielle 2. Le langage Lisp, dont le nom vient de list processing, repose lui aussi sur la liste 3.
Exercices corrigés
Exercice 1 Lire une liste après plusieurs opérations
On part d'une liste vide. On exécute dans l'ordre :
l = Liste()
l.ajouter_en_tete(4)
l.ajouter_en_tete(7)
l.ajouter_en_tete(2)
l.ajouter_en_queue(9)
Quelle est la valeur de l.acces(2) (indices à partir de 0) ?
Indice 1
Dessine la liste après chaque instruction : l'ajout en tête place l'élément avant tous les autres.
Indice 2
L'ajout en queue place 9 après le dernier élément.
Voir la correction pas à pas
Après
ajouter_en_tete(4): la liste est .Après
ajouter_en_tete(7): on place 7 devant, la liste est .Après
ajouter_en_tete(2): la liste est .Après
ajouter_en_queue(9): la liste est .L'indice 0 est 2, l'indice 1 est 7, l'indice 2 est 4. On suit deux liens depuis la tête.
l.acces(2) vaut 4. Le piège est de croire que le premier élément ajouté (4) reste en tête : l'ajout en tête le repousse vers la fin.
Exercice 2 Écrire une fonction de comptage
Écris une méthode compter(self, x) de la classe Liste qui renvoie le nombre de cellules dont la valeur est égale à x. Précise ce qu'elle renvoie sur une liste vide, puis applique-la à la liste avec .
Indice 1
Utilise le même schéma de parcours que pour longueur, avec un compteur.
Indice 2
Ne touche à aucun lien : ici on lit seulement.
Voir la correction pas à pas
On initialise un compteur
n = 0etcourant = self.tete.Tant que
courant is not None, on comparecourant.valeuràx; si égalité, on ajoute 1 àn.À chaque tour, on avance avec
courant = courant.suivant, sinon la boucle est infinie.À la fin de la boucle, on renvoie
n.Sur la liste vide, la boucle ne s'exécute pas et la méthode renvoie 0. Sur , trois cellules valent 3, donc la méthode renvoie 3.
def compter(self, x):
n = 0
courant = self.tete
while courant is not None:
if courant.valeur == x:
n += 1
courant = courant.suivant
return n
Le résultat sur l'exemple est 3.
Exercice 3 Supprimer toutes les occurrences
Écris une méthode supprimer_tout(self, x) qui retire de la liste toutes les cellules de valeur x, et renvoie le nombre de cellules supprimées. Fais-la fonctionner sur : liste vide, x en tête (plusieurs fois de suite), x à la fin, x absent.
Indice 1
Traite d'abord les têtes égales à x avec une boucle, avant de parcourir le reste.
Indice 2
Pour le reste, garde une référence à la cellule courante et teste courant.suivant, sans avancer quand tu supprimes.
Voir la correction pas à pas
On initialise
n = 0.Tant que la tête existe et vaut
x, on exécuteself.tete = self.tete.suivantet on incrémenten. Cela règle le cas « plusieursxau début ».Si la liste est maintenant vide, on renvoie
n. Sinon,courant = self.tete.Tant que
courant.suivantn'est pasNone: sicourant.suivant.valeur == x, on écritcourant.suivant = courant.suivant.suivantet on incrémenten, sans avancer (la nouvelle suivante peut aussi valoirx). Sinon, on avance.On renvoie
n.
def supprimer_tout(self, x):
n = 0
while self.tete is not None and self.tete.valeur == x:
self.tete = self.tete.suivant
n += 1
if self.tete is None:
return n
courant = self.tete
while courant.suivant is not None:
if courant.suivant.valeur == x:
courant.suivant = courant.suivant.suivant
n += 1
else:
courant = courant.suivant
return n
Le point délicat est de ne pas avancer après une suppression : deux x consécutifs seraient sinon mal traités.
Quiz
7 questions · correction immédiate · ton score reste sur ton appareil.
-
Le lien de la dernière cellule vaut
None, et c'est ce qui arrête les parcours. Une référence vers la tête transformerait la liste en liste circulaire, ce qui n'est pas le cas général 3.0est un entier, pas une absence de cellule. -
Faux : on ne connaît que la tête, donc il faut suivre les liens un à un. L'accès direct est la propriété des tableaux, dont les données sont contiguës en mémoire 3.
-
La nouvelle cellule doit pointer vers l'ancienne tête avant de devenir la tête. Avec
Cellule(v)ouCellule(v, None), tout le reste de la liste serait perdu.l.tete.suivant = ...écrase le deuxième maillon et plante si la liste est vide. -
Si la valeur est absente, on parcourt toute la liste avant de conclure : 8 cellules examinées. On ne peut s'arrêter plus tôt que si la valeur est trouvée. Répondre 1 reviendrait à supposer qu'on trouve la valeur en tête.
-
Il faut sauvegarder le suivant avant de modifier le lien de
c. Dans l'ordre inverse,c.suivantdésigne déjà la nouvelle cellule, qui pointerait vers elle-même : la suite de la chaîne est perdue. Modifier seulementc.suivantperd aussi toute la suite.
Les questions qu'on se pose
À quoi servent les listes chaînées si Python a déjà des listes ?
À comprendre comment une structure se construit avec des objets, et à servir de base à d'autres structures. La liste est à l'origine de types plus complexes comme la pile, la file ou les arbres 3. À l'épreuve pratique, on peut te demander d'expliquer en quoi une structure est adaptée à un exercice donné 1.
Quelle différence y a-t-il entre `None` et une liste vide ?
Dans la classe Liste de ce cours, la liste est vide quand tete vaut None ; None est la valeur du lien de fin. La liste est un objet (qui existe), None est l'absence de cellule. Cela explique pourquoi on teste self.tete is None pour savoir si la liste est vide, et non self is None.
Pourquoi mon parcours plante avec une erreur sur `None` ?
Tu as écrit un accès comme courant.suivant.valeur alors que courant.suivant valait None, ou tu as continué à avancer après la dernière cellule. Vérifie la condition de ta boucle : while courant is not None pour traiter toutes les cellules, while courant.suivant is not None pour s'arrêter sur la dernière. Pense aussi au cas de la liste vide.
Comment tester mes fonctions sur les listes chaînées ?
Écris des assertions sur les cas particuliers : liste vide, une seule cellule, premier ou dernier élément concerné, valeur absente, doublons 1. Tu peux écrire une méthode qui convertit la liste chaînée en liste Python, pour comparer facilement le résultat attendu avec assert.
Y a-t-il une limite au nombre de cellules d'une liste chaînée ?
Sources
- Ressources IREM - Structures de données NSI, Académie de Lyon. Consulté le 7 novembre 2026.
- Liste chaînée, Wikipédia. Consulté le 7 novembre 2026.
- Liste (informatique), Wikipédia. Consulté le 7 novembre 2026.
Les numéros dans le texte renvoient à ces sources. Une source qui ne dit pas ce qu'on lui fait dire ? Signale-le.