Menu
Coddy logo textTech

Liste chaînée

Dernière mise à jour

Une liste chaînée stocke une séquence sous forme de chaîne de nœuds, où chaque nœud contient une valeur et un pointeur vers le nœud suivant. Contrairement à un tableau, les nœuds ne sont pas contigus en mémoire : vous suivez les pointeurs next pour parcourir la liste. Appuyez sur lecture ci-dessus pour voir des nœuds se lier en tête et en queue, une valeur être recherchée en parcourant la chaîne, et un nœud être supprimé en recâblant un pointeur.

Insérer ou supprimer en tête est en O(1) car il suffit de repointer la tête. Atteindre une position au milieu ou en queue est en O(n) car vous devez d'abord y parcourir. Ce compromis -extrémités peu coûteuses, pas d'accès aléatoire- est ce qui distingue une liste chaînée d'un tableau.

Complexité temporelle

OpérationComplexitéNotes
Insérer en têteO(1)Repointer la tête
Insérer en queueO(n)Parcourir jusqu'à la fin d'abord (O(1) avec un pointeur de queue)
RechercherO(n)Suivre les pointeurs next
Supprimer la têteO(1)Repointer la tête au-delà d'elle
Accès par indiceO(n)Pas d'accès aléatoire

Liste chaînée vs tableau

AspectListe chaînéeTableau
MémoireNœuds dispersés + pointeursBloc contigu
Accès aléatoireO(n)O(1)
Insérer/supprimer en têteO(1)O(n) (décalage)
Compatibilité avec le cacheMauvaiseBonne

Exemple résolu

Construire la liste [10, 20], préfixer 5, puis supprimer 20 :

ÉtapeStructureAction
Débuthead -> nullListe vide
Insérer en tête 10head -> 10 -> nullRepointer la tête vers un nouveau nœud dont le next est l'ancienne tête (null)
Insérer en queue 20head -> 10 -> 20 -> nullParcourir jusqu'au nœud 10, régler son next sur un nouveau nœud 20
Insérer en tête 5head -> 5 -> 10 -> 20 -> nullLe nouveau nœud 5 pointe vers l'ancienne tête 10 ; la tête pointe maintenant vers 5
Supprimer 20head -> 5 -> 10 -> nullParcourir jusqu'à 10, régler son next de 20 sur null ; le nœud 20 est délié

Quand utiliser une liste chaînée

À utiliser quandÀ éviter quand
Vous insérez ou supprimez aux extrémités (ou à un nœud que vous détenez) bien plus que vous n'indexezVous avez besoin d'un accès aléatoire rapide par position (indexation O(1))
La taille change beaucoup et vous ne voulez pas de coût de redimensionnement/copieVous parcourez des boucles serrées où la localité du cache domine la performance
Vous construisez une file, une pile ou une liste d'adjacenceLa mémoire est limitée : chaque nœud paie un pointeur supplémentaire par élément
Vous avez besoin de références stables vers des nœuds qui survivent à des insertions ailleursVous lisez surtout et modifiez rarement, donc un tableau est plus simple et plus rapide

Code de Linked List

Une implémentation propre et exécutable de Linked List en Python, JavaScript, Java, C++, C. Choisissez un langage, copiez le code ou ouvrez-le préchargé dans le Playground Coddy.

Code de Linked List en Python

Python
1class Node:2    def __init__(self, value):3        self.value = value4        self.next = None5
6
7class LinkedList:8    def __init__(self):9        self.head = None10
11    def append(self, value):12        node = Node(value)13        if self.head is None:14            self.head = node15            return16        current = self.head17        while current.next:18            current = current.next19        current.next = node20
21    def find(self, value):22        current = self.head23        while current:24            if current.value == value:25                return True26            current = current.next27        return False28
29    def delete(self, value):30        # Re-link the previous node around the match31        current, prev = self.head, None32        while current:33            if current.value == value:34                if prev is None:35                    self.head = current.next36                else:37                    prev.next = current.next38                return True39            prev, current = current, current.next40        return False41
42    def __str__(self):43        values, current = [], self.head44        while current:45            values.append(str(current.value))46            current = current.next47        return " -> ".join(values) + " -> None"48
49
50lst = LinkedList()51for value in [3, 7, 1, 9]:52    lst.append(value)53
54print("List:    ", lst)55print("find(7): ", lst.find(7))56lst.delete(1)57print("After delete(1):", lst)
Exécutez ce code dans le Playground Python

FAQ sur les listes chaînées

Quelle est la différence entre une liste chaînée et un tableau ?
Un tableau stocke les éléments dans un seul bloc contigu, offrant un accès aléatoire O(1) mais des insertions/suppressions O(n) qui décalent les éléments. Une liste chaînée stocke les nœuds n'importe où en mémoire reliés par des pointeurs, offrant des insertions/suppressions O(1) à une position connue mais un accès O(n) puisque vous devez parcourir la chaîne.
Quand devrais-je utiliser une liste chaînée ?
Les listes chaînées brillent lorsque vous insérez ou supprimez fréquemment aux extrémités (ou à un nœud dont vous détenez déjà une référence) et avez rarement besoin d'un accès aléatoire, par exemple les files, les piles, les listes d'adjacence et les caches LRU. Si vous avez besoin d'un accès indexé rapide, un tableau ou un tableau dynamique est généralement préférable.
Quelle est la complexité temporelle d'une liste chaînée ?
Insérer ou supprimer en tête est en O(1). La recherche, ou atteindre la queue sans pointeur de queue, est en O(n) car vous suivez les pointeurs next un par un. Il n'y a pas d'accès aléatoire O(1) : indexer dans une liste chaînée est en O(n).
Quelle est la différence entre une liste simplement et doublement chaînée ?
Une liste simplement chaînée ne stocke qu'un pointeur next par nœud, vous pouvez donc parcourir dans une seule direction et supprimer un nœud nécessite une référence à son prédécesseur. Une liste doublement chaînée ajoute un pointeur prev, permettant le parcours arrière et la suppression O(1) d'un nœud détenu, au prix d'un pointeur supplémentaire par nœud et de plus de gestion à chaque insertion et suppression.
Pourquoi insérer en queue est-il O(n) si insérer en tête est O(1) ?
Insérer en tête ne recâble que le pointeur head, ce qui est un travail constant. Atteindre la queue signifie suivre les pointeurs next depuis la tête jusqu'à la fin, ce qui est en O(n). Conserver un pointeur tail séparé rend l'insertion en queue également en O(1), c'est pourquoi les listes réelles suivent souvent les deux extrémités.
Les listes chaînées ont-elles une insertion O(1) partout ?
Non, c'est une idée reçue courante. L'insertion elle-même n'est en O(1) qu'une fois que vous détenez déjà un pointeur vers le nœud après lequel vous insérez. Trouver cette position par valeur ou par indice coûte toujours O(n) car vous devez parcourir la chaîne pour y arriver.
Coddy programming languages illustration

Maîtrisez les algorithmes avec Coddy

COMMENCER