Aller au contenu
Pédagogie

Structures de données en terminale NSI : comprendre au lieu d'apprendre par cœur

Ilian, Head of ScienceIngénieur logiciel et professeur particulier

Les structures de données de terminale NSI ne s'apprennent pas par leur définition mais par le problème qu'elles résolvent. Une pile n'est pas « une structure LIFO » : c'est ce qu'on utilise quand on doit revenir en arrière. Poser la question dans ce sens rend le chapitre nettement plus simple, et c'est aussi ce que le jury attend.

Pourquoi ce chapitre paraît-il si abstrait ?

La plupart des élèves apprennent ce chapitre comme du vocabulaire : pile égale LIFO, file égale FIFO, arbre égale hiérarchie. Ils récitent correctement et se retrouvent bloqués dès qu'un exercice demande de choisir la bonne structure, parce que la définition ne dit rien sur le moment où il faut l'utiliser.

L'ordre utile est inverse. On part du problème, on regarde quelles opérations il exige, et la structure s'impose d'elle-même. Une fois ce réflexe installé, les définitions deviennent inutiles à mémoriser : elles se retrouvent.

La pile : quand il faut pouvoir revenir en arrière

Une pile sert à retenir un chemin pour le défaire. C'est la structure du bouton annuler, du bouton retour d'un navigateur, et de la vérification de parenthèses. C'est aussi ce que la machine utilise elle-même pour gérer les appels de fonctions, ce qui explique pourquoi la récursivité et les piles sont enseignées ensemble.

Vérifier qu'une expression est bien parenthésée
Exemple
def bien_parenthesee(expr):
    pile = []
    for c in expr:
        if c == "(":
            pile.append(c)
        elif c == ")":
            if not pile:        # une fermante sans ouvrante
                return False
            pile.pop()
    return len(pile) == 0       # rien ne doit rester ouvert

print(bien_parenthesee("(a+(b*c))"))   # True
print(bien_parenthesee("(a+b))"))      # False

Le test final len(pile) == 0 est celui que les élèves oublient le plus souvent. Sans lui, « ((a) » est déclaré correct.

En Python, une liste fait très bien l'affaire : append pour empiler, pop pour dépiler. Il n'est pas nécessaire d'écrire une classe, sauf si l'énoncé le demande explicitement.

La file : quand l'ordre d'arrivée doit être respecté

Une file sert quand le premier arrivé doit être le premier traité : une file d'attente, une file d'impression, les messages à envoyer. Elle apparaît aussi dans le parcours en largeur d'un arbre ou d'un graphe, qui est l'un des algorithmes les plus demandés en terminale.

Le piège de performance que personne ne mentionne
À éviter
file = []
file.append("a")
premier = file.pop(0)   # retire en tête : coûteux
Correct
from collections import deque

file = deque()
file.append("a")
premier = file.popleft()   # retire en tête : immédiat

pop(0) oblige Python à décaler tous les éléments restants. Sur un exercice de lycée cela ne se voit pas, mais c'est exactement le genre de remarque qui fait la différence en soutenance ou face à une question sur la complexité.

L'arbre : quand les données ont une hiérarchie

Un arbre représente ce qui se ramifie : un système de fichiers, un arbre généalogique, les coups possibles dans un jeu. En terminale, l'arbre binaire de recherche est le cas central, parce qu'il permet de chercher rapidement dans un ensemble ordonné.

L'intuition à retenir : chercher dans un arbre binaire de recherche équilibré revient à couper le problème en deux à chaque étape, comme quand on cherche un mot dans un dictionnaire papier.

Trouver une valeur parmi 1 000 éléments, dans le pire des cas
1 000
comparaisons
en parcourant une liste
10
comparaisons
dans un arbre équilibré
×100
de travail en moins
et l'écart grandit avec la taille
Comparaisons dans un arbre binaire de recherche équilibré
100 éléments100 éléments : 7 comparaisons71 000 éléments1 000 éléments : 10 comparaisons1010 000 éléments10 000 éléments : 14 comparaisons14100 000 éléments100 000 éléments : 17 comparaisons17

Valeurs exactes : hauteur minimale d'un arbre binaire à n noeuds, soit la partie entière supérieure de log2(n+1).

Multiplier la taille des données par mille ne coûte que dix comparaisons de plus. C'est toute la raison d'être des arbres, et c'est la réponse attendue à la question « pourquoi ne pas se contenter d'une liste ». Elle fait aussi une très bonne question de Grand oral.

Un arbre binaire minimal et son parcours infixe
Exemple
# Un noeud : (valeur, sous-arbre gauche, sous-arbre droit)
# None represente un arbre vide.
arbre = (8, (3, None, None), (12, None, None))

def infixe(a):
    if a is None:
        return []
    valeur, gauche, droit = a
    return infixe(gauche) + [valeur] + infixe(droit)

print(infixe(arbre))   # [3, 8, 12] : trié

Le parcours infixe d'un arbre binaire de recherche renvoie les valeurs triées. C'est le résultat le plus souvent demandé et le plus souvent oublié.

Le graphe : quand tout peut être relié à tout

Un graphe généralise l'arbre : les liens n'ont plus de hiérarchie et les cycles sont autorisés. Réseau social, plan de métro, réseau informatique. Deux représentations sont au programme, et le choix entre elles est une question d'examen fréquente.

CritèreMatrice d'adjacenceListe d'adjacence
FormeUn tableau à deux dimensionsUn dictionnaire sommet vers voisins
« Ces deux sommets sont-ils reliés ? »Réponse immédiateIl faut parcourir la liste des voisins
Place occupéeLe carré du nombre de sommets, même si le graphe est videProportionnelle au nombre d'arêtes réelles
À choisir quandLe graphe est petit et très connectéPar défaut : les graphes réels ont peu d'arêtes
Parcours en largeur avec une file
Exemple
from collections import deque

graphe = {
    "A": ["B", "C"],
    "B": ["A", "D"],
    "C": ["A"],
    "D": ["B"],
}

def parcours_largeur(g, depart):
    vus = {depart}
    file = deque([depart])
    ordre = []
    while file:
        s = file.popleft()
        ordre.append(s)
        for voisin in g[s]:
            if voisin not in vus:
                vus.add(voisin)
                file.append(voisin)
    return ordre

print(parcours_largeur(graphe, "A"))   # ['A', 'B', 'C', 'D']

L'ensemble vus est indispensable : sans lui, un cycle fait tourner le programme indéfiniment. C'est l'erreur la plus fréquente sur les graphes.

Quelle structure de données choisir ?

Du problème vers la structure, jamais l'inverse
Le problèmeLa structureExemples typiques
Je dois revenir en arrièrePileAnnulation, parenthésage, mémoire des appels, labyrinthe
Je traite dans l'ordre d'arrivéeFileFile d'attente, parcours en largeur, tâches successives
Mes données sont hiérarchiquesArbreDossiers, classification, recherche dans un ensemble ordonné
Tout peut être relié à toutGrapheRéseau, itinéraires, relations. Liste d'adjacence par défaut
Je cherche par une cléDictionnaireAccès direct par identifiant. Souvent oubliée car trop simple

Sources et ressources

Questions fréquentes

On me demande souvent

Faut-il implémenter les piles et les files avec des classes en NSI ?
Seulement si l'énoncé le demande. Le programme met l'accent sur l'interface, c'est-à-dire les opérations disponibles, plus que sur la manière de les coder. Une liste Python suffit pour une pile.
Pourquoi la récursivité revient-elle partout dans ce chapitre ?
Parce qu'un arbre est défini de façon récursive : un arbre est une valeur et deux sous-arbres. La compréhension des références est le prérequis, et c'est là que butent la plupart des élèves : voir les erreurs Python les plus fréquentes. Écrire une fonction récursive suit alors exactement la forme de la structure, ce qui la rend plus simple qu'une version itérative.
Comment réviser efficacement les structures de données ?
En partant d'énoncés plutôt que du cours. Prenez dix situations concrètes, décidez quelle structure convient et pourquoi, puis vérifiez. C'est exactement la compétence évaluée, et c'est plus rapide que de relire le chapitre.

Cette page fait partie du dossier cours particuliers de nsi (spécialité lycée).

Le chapitre qui décide de l'année

Les structures de données conditionnent presque tout le programme de terminale. Les reprendre tôt coûte quelques séances, les reprendre en avril coûte beaucoup plus cher.

Tout démarre par une heure d'évaluation sans engagement : on situe le niveau, on construit le programme, et le tarif en découle.