☀️ Stage Pré-rentrée · dès le 24 aoûtRéserver ma place →
Majorant
📘 Fiche de cours · 1re année📐 MPSI💻 Informatique Informatique communeNiveau · Sup

Complexité temporelle

Lire la complexité d'un code à l'œil : la notation grand-O, la table des ordres de grandeur, meilleur cas contre pire cas sur la recherche séquentielle, et la méthode boucle→O(n) / imbriquée→O(n²) / division par 2→O(log n) — avec la preuve du coût logarithmique de la dichotomie et trois exercices corrigés.

Fiche rédigée par les mentors Majorant — alumni Polytechnique, CentraleSupélec et Mines Paris.

1 définitions1 théorèmes1 démos à savoirMis à jour le 2026-08-02

Vue d'ensemble

Deux programmes peuvent donner le même résultat et pourtant l'un s'exécuter en une fraction de seconde, l'autre mettre des heures sur une grande entrée. Pour comparer des algorithmes sans dépendre de la machine, on ne mesure pas un temps en secondes : on compte le nombre d'opérations élémentaires en fonction de la taille n de l'entrée. La notation grand-O résume ce décompte en un ordre de grandeur (, , …). Cette fiche te montre comment lire la complexité d'un code à l'œil, en décryptant chaque exemple ligne par ligne.

Au programme (tronc commun, 1re année — BO 2021) — Coût d'un algorithme : nombre d'opérations élémentaires en fonction de la taille des entrées ; notation ; complexité dans le meilleur et le pire des cas ; ordres de grandeur usuels (constant, logarithmique, linéaire, quadratique, exponentiel) sur les algorithmes du programme.

Prérequis

  • Écrire et lire une boucle for et une boucle while
  • Connaître la recherche par dichotomie dans un tableau trié
  • Savoir ce qu'est le logarithme en base 2 : est l'exposant tel que
🎯 Accompagnement Majorant

« Comment je sais si c'est du ou du rien qu'en regardant ? » C'est un réflexe qui se travaille, et il rapporte des points à chaque écrit. Nos mentors alumni X · Centrale · Mines t'entraînent à lire la complexité d'un code d'un coup d'œil, sur tes propres sujets, jusqu'à ce que ça devienne automatique.

Trouver un mentor →

1. Compter les opérations, pas les secondes

Le temps réel d'un programme dépend de la machine, du langage, de ce que fait l'ordinateur à côté : ce n'est pas une bonne mesure pour comparer des algorithmes. On raisonne donc sur le nombre d'opérations élémentaires effectuées (une addition, une comparaison, un accès t[i], une affectation…) en fonction de la taille de l'entrée, notée n (le nombre d'éléments d'une liste, la valeur d'un entier, etc.).

Définition 1.1 — Complexité temporelle et notation grand-O

La complexité temporelle d'un algorithme est une fonction qui donne le nombre d'opérations élémentaires effectuées sur une entrée de taille . On s'intéresse à son ordre de grandeur pour grand, à une constante multiplicative près. On écrit , et on lit « est un grand-O de », lorsqu'il existe une constante C > 0 et un rang tels que :

📝 Pourquoi « à une constante près ». Si un algorithme fait opérations et un autre opérations, les deux sont en : pour grand, le facteur et le +7 ne changent pas la catégorie. Le grand-O gomme les constantes et les termes négligeables pour ne garder que le terme dominant : est en .

Prenons un premier exemple : la somme des éléments d'une liste.

def somme(t):
    s = 0
    for x in t:
        s = s + x
    return s
🔍 Décryptage ligne par ligne
s = 0Une affectation : 1 opération, faite une seule fois quelle que soit la taille de t.
for x in t:La boucle parcourt les éléments. Le corps de la boucle est donc exécuté fois — c'est lui qui va donner l'ordre de grandeur.
s = s + xUne addition + une affectation à chaque tour, donc environ opérations en tout. C'est le cœur du coût.
return s1 opération, une seule fois.
💡 Le décompte. Au total opérations (à la louche). Le terme dominant est , donc somme est en : on dit qu'elle a une complexité linéaire. Doubler la taille de la liste double (à peu près) le travail.

2. Les familles d'ordres de grandeur

Presque toute la complexité au programme se range dans une poignée de familles. Le tableau ci-dessous est la chose à avoir en tête : il donne, pour chaque famille, le nombre d'opérations quand l'entrée grandit. C'est notre « table de trace » — elle trace non pas l'exécution d'un code, mais l'explosion du nombre d'opérations selon .

Ordres de grandeur — nombre d'opérations selon la taille de l'entrée
FamilleNom
constant111
logarithmique≈ 3≈ 7≈ 20
linéaire10100106
quasi-linéaire≈ 33≈ 664≈ 2 × 107
quadratique10010 0001012
exponentiel1024≈ 1030inimaginable
📝 Lire ce tableau. Entre et , un algorithme passe de 3 à 20 opérations : quasi gratuit. Un passe de 100 à : mille milliards d'opérations, soit des minutes voire des heures. Et est déjà hors-jeu dès ( : même à un milliard d'opérations par seconde, il faudrait près de 3000 fois l'âge de l'univers pour terminer un seul calcul). La famille compte infiniment plus que la constante devant.
n'est pas « toujours plus lent » que . Le grand-O parle du comportement pour grand. Sur une petite entrée, un algorithme avec une petite constante peut battre un avec une grosse constante. Ce que garantit le grand-O, c'est qu'à partir d'un certain rang , le linéaire l'emporte — et cet écart devient vite gigantesque.

3. Meilleur cas, pire cas, cas moyen

Pour une même taille , le nombre d'opérations peut dépendre du contenu de l'entrée. On distingue alors trois complexités. L'exemple canonique est la recherche séquentielle : parcourir une liste jusqu'à trouver une valeur.

def recherche_seq(t, x):
    for i in range(len(t)):
        if t[i] == x:
            return i          # trouvé : on renvoie la position
    return -1                 # jamais trouvé : x est absent
🔍 Décryptage ligne par ligne
for i in range(len(t)):On balaie les indices de à . Le nombre de tours réellement effectués dépend de se trouve x.
if t[i] == x: return iUne comparaison par tour. Dès qu'on tombe sur x, on renvoie son indice et on s'arrête net : on ne fait pas les tours suivants.
return -1Si la boucle va jusqu'au bout sans rien trouver, x est absent : on a fait comparaisons pour rien.
  • Meilleur casx est en première position (t[0]) : 1 comparaison, donc .
  • Pire casx est en dernière position, ou absent : comparaisons, donc .
  • Cas moyen — si x est présent à une position au hasard : en moyenne comparaisons, soit encore .
📝 La convention par défaut. Quand on dit « la recherche séquentielle est en » sans préciser, on parle du pire cas : c'est la garantie la plus utile (« ça ne fera jamais plus que… »). Sauf mention contraire, complexité = complexité dans le pire cas.

4. Méthode : lire la complexité d'un code

📐 Méthode — déterminer la complexité d'un code.
  1. Une boucle qui parcourt éléments (et corps en ) → .
  2. Deux boucles imbriquées, chacune sur → le corps s'exécute fois → .
  3. Une grandeur divisée par 2 à chaque tour (comme la dichotomie) → .
  4. Des blocs en séquence (l'un après l'autre) → on additionne les coûts et on garde le plus grand : .
  5. On oublie les constantes et les termes non dominants.

Deux boucles imbriquées → quadratique

Comptons les paires d'éléments d'une liste dont la somme vaut une valeur cible s.

def compte_paires(t, s):
    n = len(t)
    c = 0
    for i in range(n):
        for j in range(i + 1, n):
            if t[i] + t[j] == s:
                c = c + 1
    return c
🔍 Décryptage ligne par ligne
for i in range(n):Boucle externe : tours, un pour chaque premier élément de la paire.
for j in range(i + 1, n):Boucle interne : pour chaque i, on essaie tous les j > i. On teste ainsi chaque paire une seule fois. Le nombre total de tours internes est .
if t[i] + t[j] == s: c = c + 1Une addition + une comparaison par paire. C'est le corps en , répété fois.
💡 Le décompte. Le corps s'exécute fois. Le terme dominant est : à une constante près, c'est , quadratique. Pour , cela fait paires testées. Doubler multiplie le travail par ≈ 4.

Division par 2 → logarithmique

La dichotomie (vue en prérequis) illustre le cas : à chaque tour, la zone de recherche est divisée par 2.

def dichotomie(t, x):
    g, d = 0, len(t) - 1
    while g <= d:
        m = (g + d) // 2
        if t[m] == x:
            return m
        elif t[m] < x:
            g = m + 1          # on jette la moitié gauche
        else:
            d = m - 1          # on jette la moitié droite
    return -1
🔍 Décryptage ligne par ligne
while g <= d:On répète tant que la zone est non vide. La question de complexité, c'est : combien de fois cette boucle tourne-t-elle ?
m = (g + d) // 2On vise le milieu de la zone courante — coût .
g = m + 1Cas « trop petit » : on garde la moitié droite. La taille de la zone est (au moins) divisée par 2.
d = m - 1Cas « trop grand » : on garde la moitié gauche. Là encore, la zone est divisée par 2.

Partant de éléments, la taille de la zone suit jusqu'à 1. Le nombre de divisions par 2 pour passer de à 1 est : la boucle fait de l'ordre de tours, d'où la complexité . C'est ce que précise le théorème suivant.

Propriété 4.1 — Coût de la dichotomie ★ À savoir démontrer

Sur un tableau trié de éléments, la recherche par dichotomie effectue au plus itérations de la boucle. Sa complexité dans le pire cas est donc .

Démonstration

Notons la taille de la zone de recherche , c'est-à-dire . Initialement . À chaque itération où l'on ne renvoie pas, on remplace par ou par avec ; dans les deux cas la nouvelle zone contient au plus éléments : la taille est (au moins) divisée par 2.

Après itérations, la zone contient donc au plus éléments. La boucle continue tant que la zone est non vide, soit . Or dès que \dfrac{n}{2^k} &lt; 1, c'est-à-dire 2^k &gt; n, la zone est vide et la boucle s'arrête. Cette condition est atteinte pour , car alors 2^k &gt; n. Le nombre d'itérations est donc au plus .

Chaque itération coûte , d'où un coût total en .

🎯 Accompagnement Majorant

Bloqué sur « pourquoi diviser par 2 donne un log » ? Ce genre de déclic, une fois posé clairement, ne te lâche plus. Nos mentors alumni X · Centrale · Mines reprennent la preuve avec toi et te font l'appliquer à d'autres algorithmes « diviser pour régner » de ton programme.

Trouver un mentor →

5. Exercices d'application

Fais-les sur papier avant d'ouvrir le corrigé, puis passe au quiz en bas de fiche.

Exo 1Reconnaître l'ordre de grandeurFacile

Donne la complexité (dans le pire cas) de cette fonction, en justifiant.

def maxi(t):
    m = t[0]
    for x in t:
        if x > m:
            m = x
    return m
Voir la correction détaillée
Une seule boucle for parcourt les éléments de t.
Le corps (une comparaison, parfois une affectation) coûte par tour.
Coût total : . C'est linéaire : chercher un maximum oblige à tout regarder, on ne peut pas faire mieux.
Exo 2Séquence de blocsIntermédiaire

Quelle est la complexité de f en fonction de n = len(t) ? Justifie avec la règle des blocs en séquence.

def f(t):
    n = len(t)
    s = 0
    for x in t:              # bloc A
        s = s + x
    c = 0
    for i in range(n):       # bloc B
        for j in range(n):
            c = c + 1
    return s + c
Voir la correction détaillée
Bloc A : une boucle simple sur éléments → .
Bloc B : deux boucles imbriquées, chacune sur → le corps s'exécute fois → .
Les deux blocs sont en séquence : on additionne, , et on garde le plus grand. La fonction est donc — le bloc A est négligeable devant le bloc B.
Exo 3Compter les tours d'une division par 2Difficile

Combien de fois la boucle tourne-t-elle pour n = 1000 ? Quelle est la complexité en fonction de n ?

def compte(n):
    r = 0
    while n > 1:
        r = r + 1
        n = n // 2
    return r
Voir la correction détaillée
À chaque tour, n est divisé par 2 (division entière) : .
On compte 9 tours avant que n n'atteigne 1 (la fonction renvoie donc 9). C'est cohérent avec .
En général, le nombre de tours est de l'ordre de : la complexité est . Doubler ajoute un seul tour.

Récap final — Ce qu'il faut absolument retenir

À la veille d'une khôlle ou d'un DS, parcours cette checklist : tu dois pouvoir répondre « oui, sans hésiter » à chaque question.

  • Sais-tu expliquer pourquoi on compte des opérations et non des secondes ?
  • Sais-tu donner la définition semi-formelle de (constante et rang ) ?
  • Sais-tu classer les familles , , , , , et dire laquelle explose le plus vite ?
  • Sais-tu distinguer meilleur cas, pire cas et cas moyen sur la recherche séquentielle ?
  • Sais-tu qu'une complexité annoncée sans précision est celle du pire cas ?
  • Sais-tu reconnaître à l'œil qu'une boucle simple est , deux boucles imbriquées , une division par 2 ?
  • Sais-tu appliquer la règle « blocs en séquence → on garde le max » ?
  • Sais-tu démontrer que la dichotomie fait au plus itérations ?

À savoir refaire

Débloque la fiche complète

Théorèmes, démonstrations à savoir refaire, méthodes-types et pièges de concours : crée ton compte gratuit pour tout lire. Une seule fois pour toutes les fiches et ressources Majorant.

Gratuit · vos données restent confidentielles.

Valide tes acquis

Quiz — Complexité

11 questions · une à la fois · seuil de maîtrise 80 %.

Informatique commune · SupQuiz — Complexité temporelleQuestion 1 / 11
FacileChoix unique1 pt

Un camarade dit : « mon algorithme met 0,3 seconde sur mon portable ». En quoi cette mesure est-elle un mauvais indicateur de la complexité temporelle de l'algorithme ?

Sélectionne une réponse pour valider.

Fiches associées

📐 MPSI·Informatique

Recherche par dichotomie

La recherche dichotomique dans un tableau trié, expliquée ligne par ligne : code Python commenté, exécution pas à pas, preuve de terminaison et de correction (variant \(d-g\), invariant de boucle), version récursive et complexité \(O(\log n)\).

📐 MPSI·Informatique

Variables, types et affectations

Les briques de base de Python pour bien démarrer la prépa : affectation, types int/float/bool/str, conversions, opérateurs (/ // %), f-strings — avec les pièges classiques et deux exercices corrigés.

📐 MPSI·Informatique

Conditions et booléens

Faire choisir un programme : booléens, comparaisons, if / elif / else, rôle de l'indentation, et combinaison de conditions avec and / or / not — avec pièges et exercices corrigés.

📐 MPSI·Informatique

Boucles for et while

Répéter une action : boucle for avec range, boucle while qui termine, et le motif de l'accumulateur (somme, compteur) — avec table de trace, pièges et exercices corrigés.

📐 MPSI·Informatique

Fonctions : paramètres et valeurs de retour

Définir et appeler une fonction, comprendre paramètres et valeur de retour, et surtout ne jamais confondre return (renvoie) et print (affiche) — avec pièges et exercices corrigés.

📐 MPSI·Informatique

Listes et chaînes de caractères

Créer, indexer, parcourir et découper des listes et des chaînes ; comprendre qu'une liste est modifiable et une chaîne non — avec les pièges d'indices et deux exercices corrigés.

Tu veux aller plus loin sur ce chapitre ?

Nos mentors alumni de Polytechnique, CentraleSupélec et Mines Paris t'accompagnent en cours particuliers — démonstrations détaillées, exos type concours, oraux blancs.

Trouver un mentor →