⛓️algorithmes

Les listes chainees en Python : implementation complete

30 mars 2026 5 min de lecture

Introduction : Pourquoi étudier les listes chaînées en NSI ?

Salut ! Si tu es en Terminale NSI, tu as déjà manipulé les listes natives de Python. Elles sont pratiques, mais sais-tu comment elles fonctionnent vraiment "sous le capot" ? Pour comprendre les structures de données, un pilier de l'informatique, il faut parfois les recréer soi-même. C'est là qu'intervient la liste chaînée. C'est une structure fondamentale, plus flexible que le tableau classique, que tu retrouveras dans de nombreux sujets de bac et projets. Dans cet article, on va plonger dans son implémentation complète en Python, pas à pas.

Le principe fondamental : des maillons et des chaînes

Contrairement à une liste Python qui stocke ses éléments dans un bloc de mémoire contigu, une liste chaînée les disperse. Chaque élément, appelé nœud (ou maillon), contient deux choses : la donnée utile (data) et une référence (un "lien") vers le nœud suivant. Le dernier nœud pointe vers une valeur spéciale, None, qui marque la fin de la chaîne.

Imagine une chasse au trésor où chaque indice te mène au suivant. C'est le principe ! Cette organisation a des conséquences majeures :

  • Avantage : L'insertion ou la suppression d'un élément au milieu est très rapide (complexité O(1) si on a déjà la position), car il suffit de modifier quelques liens, sans avoir à décaler tous les autres éléments comme dans un tableau.
  • Inconvénient : L'accès à un élément à un index donné est lent (complexité O(n)), car on doit parcourir la chaîne depuis le début. On parle d'accès séquentiel, et non aléatoire.

Implémentation pas à pas en Python

On va construire notre liste chaînée en deux temps : d'abord la classe pour le nœud, puis la classe pour la liste elle-même qui gérera ces nœuds.

Étape 1 : La classe Node (le nœud)

Chaque maillon de notre chaîne est un objet simple. On le définit avec un constructeur (__init__) qui initialise la donnée et le lien vers le suivant.

class Node:
"""Classe représentant un nœud (ou maillon) d'une liste chaînée."""
def __init__(self, data):
self.data = data # La valeur stockée
self.next = None # Le lien vers le nœud suivant. Par défaut, il n'y en a pas.

C'est tout ! self.next sera soit un autre objet Node, soit None.

Étape 2 : La classe LinkedList (la liste)

Cette classe va gérer l'ensemble. Elle a juste besoin de connaître la tête (head), c'est-à-dire le premier nœud de la chaîne.

class LinkedList:
"""Classe représentant la liste chaînée elle-même."""
def __init__(self):
self.head = None # Au début, la liste est vide

Étape 3 : Ajouter des méthodes essentielles

Une liste inerte ne sert à rien. Implémentons les opérations de base.

Ajout en fin de liste (append)

Il faut parcourir toute la liste jusqu'au dernier nœud (celui dont next est None) et lui attacher un nouveau nœud.

def append(self, data):
"""Ajoute un élément à la fin de la liste."""
new_node = Node(data)
if self.head is None: # Si la liste est vide
self.head = new_node
return
last_node = self.head
while last_node.next: # On avance jusqu'au dernier nœud
last_node = last_node.next
last_node.next = new_node # On attache le nouveau nœud

Affichage de la liste (__str__)

Pour visualiser notre liste, on surcharge la méthode __str__. On parcourt et on accumule les données dans une chaîne.

def __str__(self):
"""Retourne une représentation lisible de la liste."""
nodes = []
current_node = self.head
while current_node:
nodes.append(str(current_node.data))
current_node = current_node.next
return " -> ".join(nodes) + " -> None"

Insertion à une position donnée (insert)

C'est là que la liste chaînée montre sa force. On trouve le nœud à la position précédente, et on ajuste les liens.

def insert(self, data, position):
"""Insère un élément à l'index 'position' (en partant de 0)."""
if position == 0:
new_node = Node(data)
new_node.next = self.head
self.head = new_node
return
current_node = self.head
for i in range(position - 1):
if current_node is None:
raise IndexError("Position hors de la liste")
current_node = current_node.next
if current_node is None:
raise IndexError("Position hors de la liste")
new_node = Node(data)
new_node.next = current_node.next
current_node.next = new_node

Comparaison avec les listes natives de Python

Maintenant que tu as implémenté ta propre liste, voyons un tableau comparatif pour bien cerner les différences.

  • Performance à l'insertion/suppression (milieu) :
    Liste chaînée : Excellente (O(1) après recherche du point d'insertion).
    Liste Python : Moyenne à mauvaise (O(n), car décalage des éléments).
  • Performance à l'accès par index (lecture) :
    Liste chaînée : Mauvaise (O(n), parcours séquentiel obligatoire).
    Liste Python : Excellente (O(1), accès direct).
  • Utilisation mémoire :
    Liste chaînée : Légèrement plus gourmande à cause du stockage des références (next).
    Liste Python : Plus efficace pour le stockage contigu de petits éléments.

En résumé, les listes natives de Python sont en réalité implémentées comme des tableaux dynamiques, pas comme des listes chaînées. Elles optimisent l'accès rapide, ce qui est le cas d'usage le plus fréquent.

Aller plus loin : listes doublement chaînées et applications

Notre liste est simplement chaînée : on ne peut la parcourir que dans un sens. Pour la NSI, tu dois aussi connaître le concept de liste doublement chaînée. Chaque nœud a alors un lien vers le suivant (next) ET vers le précédent (prev). Cela permet un parcours dans les deux sens et simplifie certaines suppressions, au prix d'une gestion un peu plus complexe.

Où retrouve-t-on ces structures ? Partout !

  • L'historique de navigation de ton navigateur (précédent/suivant).
  • La gestion de la mémoire dans certains systèmes.
  • La file (deque du module collections en Python) utilise une liste doublement chaînée pour des ajouts/suppressions rapides aux deux extrémités.

Implémenter une liste chaînée n'est pas qu'un exercice académique. C'est une porte d'entrée vers la compréhension profonde de l'algorithmique et de la gestion des données, des compétences centrales pour ton bac et tes futures études.

📚 Pour aller plus loin

Questions fréquentes

Quelle est la différence principale entre une liste Python et une liste chaînée ?

La différence fondamentale est l'organisation en mémoire. Une liste Python (tableau dynamique) stocke ses éléments dans un bloc contigu, permettant un accès direct très rapide à n'importe quel index. Une liste chaînée disperse ses éléments (nœuds) dans la mémoire, chaque nœud pointant vers le suivant. Cela rend l'accès par index lent (parcours obligatoire), mais les insertions/suppressions au milieu sont plus efficaces car il suffit de modifier des liens, sans décaler tous les éléments.

Pourquoi la complexité d'accès à un élément est-elle O(n) dans une liste chaînée ?

Parce qu'il n'y a pas d'index direct. Pour atteindre le 5ème élément, l'algorithme doit obligatoirement démarrer au premier nœud (head), suivre le lien `next` vers le 2ème, puis vers le 3ème, le 4ème, et enfin le 5ème. Dans le pire des cas (accéder au dernier élément), il parcourt tous les n éléments de la liste, d'où une complexité linéaire O(n). C'est ce qu'on appelle un accès séquentiel.

Dans quels cas pratiques utiliserais-je une liste chaînée plutôt qu'une liste classique ?

Tu utiliserais une liste chaînée quand ton algorithme fait beaucoup d'insertions ou de suppressions fréquentes au milieu d'une grande collection de données, et peu d'accès aléatoires par index. Un exemple classique est un éditeur de texte qui utilise une liste chaînée pour représenter les lignes : insérer ou supprimer un caractère au milieu d'une ligne est très rapide. Cependant, en Python, pour la plupart des usages, la liste native (optimisée en C) reste le meilleur choix. Comprendre les listes chaînées sert surtout à maîtriser les concepts pour des structures plus complexes (arbres, graphes) ou d'autres langages.

Comment supprimer un nœud d'une liste chaînée ?

Pour supprimer un nœud, il faut trouver le nœud qui le précède (sauf si c'est la tête), et faire pointer son lien `next` vers le nœud qui suit celui à supprimer. Cela "détache" le nœud de la chaîne. Par exemple, pour supprimer le nœud B dans la chaîne A -> B -> C, on modifie le lien `next` de A pour qu'il pointe directement vers C (A -> C). Le nœud B, n'étant plus référencé, sera ensuite nettoyé par le ramasse-miettes de Python. Il faut aussi gérer le cas particulier de la suppression de la tête de liste.

Bravo ! Tu as lu cet article
Inscris-toi pour sauvegarder ta progression et gagner des XP
Creer mon compte
liste chainee PythonNSI terminale
Pixel