Objectifs de cette leçon
- Comprendre la structure d'une liste chaînée
- Implémenter l'ajout et la suppression de nœuds
- Comparer listes chaînées et tableaux
Listes chaînées 🔗
Imagine une chasse au trésor : chaque indice te donne un morceau de la carte ET te dit où trouver le prochain indice. C'est exactement comme ça que marche une liste chaînée !
1. Pourquoi pas un tableau ? 🤔
Les tableaux (listes classiques) ont des défauts :
- 🔴 Taille fixe (dans beaucoup de langages, on doit décider la taille à l'avance)
- 🔴 Insérer au milieu = décaler tous les éléments → O(n)
- 🔴 Supprimer au milieu = re-décaler → O(n)
Exemple : Dans un tableau de 1000 éléments, insérer au début force les 1000 éléments à se décaler de 1 case. C'est lent !
Une liste chaînée résout ces problèmes : chaque élément connaît son voisin, on peut insérer/supprimer sans tout décaler.
2. La structure : des nœuds et des pointeurs 🧱
Une liste chaînée est composée de nœuds reliés entre eux. Chaque nœud contient :
- Une valeur (la donnée)
- Un pointeur vers le prochain nœud (ou
Nonesi c'est le dernier)
Exécution pas à pas
pseudo1/5▶️STRUCTURE NoeudSTRUCTURE NoeudLe programme exécute cette action, puis passe à la suivante.Le programme exécute cette instruction, puis passe à la suivante.
class Noeud: def __init__(self, valeur): self.valeur = valeur # La donnée self.suivant = None # Le pointeur vers le suivant (None = dernier)
💡 Visualisation :
head → [10 | •] → [20 | •] → [30 | None]
headpointe vers le premier nœud (10)- Chaque nœud pointe vers le suivant
- Le dernier pointe vers
None(fin de la liste)
3. Opération : ajouter au début 🔝
C'est l'opération la plus rapide : on crée un nœud, on le branche devant, et on déplace la tête.
Exécution pas à pas
pseudo1/6🧩FONCTION ajouter_debut(liste, valeur)FONCTION ajouter_debut(liste, valeur)Le programme exécute cette action, puis passe à la suivante.On définit une fonction appelée "ajouter_debut(liste, valeur)". Cette fonction contient des instructions qui seront exécutées quand on l'appelle.
def ajouter_debut(self, valeur): noeud = Noeud(valeur) noeud.suivant = self.tete # Le nouveau pointe vers l'ancien premier self.tete = noeud # La tête devient le nouveau
Pas à pas : Liste = [10 → 20], on ajoute 5 au début :
- On crée un nœud (5)
- 5.suivant → 10
- tête → 5 → Résultat : [5 → 10 → 20] ✅
4. Opération : ajouter à la fin 🔚
On doit parcourir toute la liste pour trouver le dernier nœud, puis lui ajouter un suivant.
Exécution pas à pas
pseudo1/12🧩FONCTION ajouter_fin(liste, valeur)FONCTION ajouter_fin(liste, valeur)Le programme exécute cette action, puis passe à la suivante.On définit une fonction appelée "ajouter_fin(liste, valeur)". Cette fonction contient des instructions qui seront exécutées quand on l'appelle.
def ajouter_fin(self, valeur): if not self.tete: self.tete = Noeud(valeur) return courant = self.tete while courant.suivant: # On avance jusqu'au dernier nœud courant = courant.suivant courant.suivant = Noeud(valeur) # On accroche le nouveau à la fin
Pas à pas : Liste = [10 → 20], on ajoute 30 à la fin :
- courant = tête[10]
- 10.suivant existe → courant = [20]
- 20.suivant = None → on s'arrête
- 20.suivant → [30] → Résultat : [10 → 20 → 30] ✅
5. Opération : supprimer une valeur 🗑️
On cherche la valeur à supprimer, et on "saute" par-dessus le nœud.
Exécution pas à pas
pseudo1/16🧩FONCTION supprimer(liste, valeur)FONCTION supprimer(liste, valeur)Le programme exécute cette action, puis passe à la suivante.On définit une fonction appelée "supprimer(liste, valeur)". Cette fonction contient des instructions qui seront exécutées quand on l'appelle.
def supprimer(self, valeur): if not self.tete: return if self.tete.valeur == valeur: # Si c'est le premier élément self.tete = self.tete.suivant # On déplace la tête return courant = self.tete while courant.suivant: if courant.suivant.valeur == valeur: courant.suivant = courant.suivant.suivant # On saute le nœud ! return courant = courant.suivant
Visuellement :
head → [10 | •] → [20 | •] → [30 | None]Si on supprime 20 :head → [10 | •] ─────────→ [30 | None]Le nœud 20 n'est plus dans la chaîne !
6. Utilisation complète 🎮
ma_liste = ListeChainee() ma_liste.ajouter_fin(10) # [10] ma_liste.ajouter_fin(20) # [10 → 20] ma_liste.ajouter_debut(5) # [5 → 10 → 20] ma_liste.afficher() # 5 → 10 → 20 → None ma_liste.supprimer(10) # [5 → 20] ma_liste.afficher() # 5 → 20 → None
7. Tableau vs Liste chaînée : que choisir ? ⚖️
| Opération | Tableau | Liste chaînée |
|---|---|---|
| Accès direct (tab[5]) | ⚡ O(1) | 🐢 O(n) — faut parcourir |
| Ajout au début | 🐢 O(n) — tout décaler | ⚡ O(1) |
| Ajout à la fin | ⚡ O(1) | 🐢 O(n) — faut trouver la fin |
| Suppression | 🐢 O(n) | 🐢 O(n) |
| Mémoire | Continue (prévisible) | Éparpillée (flexible) |
💡 Quand utiliser une liste chaînée ?
- Tu insères/supprimes souvent au début
- Tu n'as pas besoin d'accès direct par index
- Tu ne connais pas la taille à l'avance
Exercices pour toi 🎯
1. Détection de cycle (algorithme de Floyd) 🏃
Une liste chaînée peut avoir un cycle (le dernier nœud pointe vers un ancien, créant une boucle). Comment le détecter ?
L'astuce : deux tortues, une rapide et une lente. Si la rapide rattrape la lente → il y a un cycle.
Exécution pas à pas
pseudo1/13🧩FONCTION a_cycle(tete)FONCTION a_cycle(tete)Le programme exécute cette action, puis passe à la suivante.On définit une fonction appelée "a_cycle(tete)". Cette fonction contient des instructions qui seront exécutées quand on l'appelle.
def a_cycle(tete): lent = rapide = tete while rapide and rapide.suivant: lent = lent.suivant rapide = rapide.suivant.suivant if lent == rapide: return True return False
2. Inverser une liste chaînée 🔄
Exécution pas à pas
pseudo1/12🧩FONCTION inverser(tete)FONCTION inverser(tete)Le programme exécute cette action, puis passe à la suivante.On définit une fonction appelée "inverser(tete)". Cette fonction contient des instructions qui seront exécutées quand on l'appelle.
def inverser(tete): precedent = None courant = tete while courant: suivant = courant.suivant courant.suivant = precedent # On inverse le sens du pointeur precedent = courant courant = suivant return precedent # La nouvelle tête de la liste inversée
Teste dans la Sandbox :
ma_liste = ListeChainee() ma_liste.ajouter_fin(1) ma_liste.ajouter_fin(2) ma_liste.ajouter_fin(3) ma_liste.afficher() # 1 → 2 → 3 → None # Après inversion : 3 → 2 → 1 → None
⚡ Simulateur — Listes chaînées
Étape 1/20On commence avec une liste vide (head → null).