cours1 min de lecture

Listes, piles, files, dictionnaires

Les structures linéaires canoniques — LIFO, FIFO, accès par index, accès par clé — caractérisées par leurs méthodes.
programme

Introduction

Une structure linéaire organise ses éléments dans un ordre — chaque élément a (au plus) un précédent et un suivant. Quatre structures dominent le programme de Terminale, qui se distinguent non par leur forme mais par leurs opérations autorisées. On retient une structure pour ce qu'elle permet, pas pour ce qu'elle contient.

Cet item demande explicitement de distinguer les structures par le jeu des méthodes qui les caractérisent et de savoir choisir la bonne en fonction de la situation.

Vue d'ensemble

StructureAccès autoriséModeOpérations clés
ListePar index [i]quelconquelen, [i], append, insert(i, x)
PileAu sommet uniquementLIFOempiler, depiler, sommet
FileTête et queue séparéesFIFOenfiler, defiler
DictionnairePar clénon ordonné conceptuellementd[k], d[k] = v, del d[k], k in d
LIFO = Last In, First Out — comme une pile d'assiettes. FIFO = First In, First Out — comme une file d'attente. Ces deux acronymes sont exigibles au baccalauréat.

Une structure dans laquelle le dernier ajouté est le premier retiré est…

La pile (LIFO)

Une pile fonctionne comme une pile d'assiettes dans un placard : la dernière posée est la première reprise, et l'on n'accède qu'au sommet. Implémentation directe par liste Python — on opère toujours à la fin de la liste, ce qui est en O(1)\mathcal{O}(1) amorti :

class Pile:
    def __init__(self):
        self._data = []
    def empiler(self, x):
        self._data.append(x)
    def depiler(self):
        if not self._data:
            raise IndexError("pile vide")
        return self._data.pop()
    def sommet(self):
        return self._data[-1]
    def est_vide(self):
        return not self._data

Cas d'usage typiques : pile d'appels d'un programme récursif, retour-arrière (navigation web, undo), parcours en profondeur d'un graphe.

La file (FIFO)

Une file fonctionne comme une salle d'attente chez le médecin : on arrive par la fin, on passe par le début, dans l'ordre d'arrivée. On a vu au cours précédent deux implémentations (par liste, par deux piles). L'implémentation idiomatique en Python utilise collections.deque, qui offre le O(1)\mathcal{O}(1) aux deux extrémités :

from collections import deque

class File:
    def __init__(self):
        self._data = deque()
    def enfiler(self, x):
        self._data.append(x)
    def defiler(self):
        if not self._data:
            raise IndexError("file vide")
        return self._data.popleft()
    def est_vide(self):
        return not self._data

Cas d'usage : file d'impression, parcours en largeur d'un graphe, gestion de tâches en attente.

Le dictionnaire

Un dictionnaire associe des clés à des valeurs — comme un annuaire téléphonique associe un nom à un numéro. On y accède par clé, pas par position. Les clés sont uniques. En Python, c'est le type dict.

notes = {"Alice": 14, "Bob": 11, "Camille": 16}
notes["Alice"]          # 14
notes["Dimitri"] = 9    # ajout
"Bob" in notes          # True
del notes["Bob"]

Recherche d'une valeur :

  • Dans une liste, chercher si x est présent coûte O(n)\mathcal{O}(n) en moyenne.
  • Dans un dictionnaire, k in d coûte O(1)\mathcal{O}(1) en moyenne grâce à une table de hachage interne — c'est l'un des grands avantages structurels.
Si vos données ont une clé naturelle (identifiant, nom, code), préférez un dictionnaire à une liste. Vous gagnez un facteur nn sur les recherches.

Quelle structure offre la recherche par clé en mathcalO(1)\mathcal(1)mathcalO(1) moyen ?

Choisir la bonne structure

Question à se poserStructure adaptée
Ai-je besoin d'accéder par position ?liste
Le dernier entré sort en premier ?pile
Le premier entré sort en premier ?file
J'identifie mes données par une étiquette ?dictionnaire
Une liste n'est pas une pile : tant que vous utilisez .append et .pop en bout, oui ; dès que vous faites .pop(0) ou .insert(0, x), vous trahissez la sémantique et payez en O(n)\mathcal{O}(n). Le choix sémantique précède le choix d'implémentation.

Pour aller plus loin

Le module collections contient deux variantes utiles : deque (file double) et OrderedDict (dictionnaire qui mémorise l'ordre d'insertion — en pratique, les dict Python 3.7+ le font par défaut).