English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

nu

invité
1 / ?
retour aux leçons

Les taux de croissance, pas les coûts absolus

Big O : mesurer à quelle vitesse les coûts augmentent

La notation Big O mesure le taux de croissance du coût d'un algorithme — pas le coût absolu.

La question que Big O répond : lorsque la taille d'entrée N double, le travail double-t-il ? Quadruple ? Reste-t-il constant ?

Le 'O' signifie 'ordre de grandeur'. L'expression entre parenthèses décrit la forme de la courbe de croissance.

Tableau de croissance Big O : opérations à N=10, 100 et 1 000 pour O(1), O(N) et O(N²)

Classes de complexité clés :

- O(1) — constante : le coût ne croît pas. Exemple : chercher une valeur par index dans un tableau. Que le tableau ait 10 éléments ou 10 millions, une recherche reste une recherche.

- O(N) — linéaire : le coût croît avec l'entrée. Exemple : lire chaque élément d'une liste une seule fois. Double la liste, double les lectures.

- O(N²) — quadratique : le coût croît comme le carré de l'entrée. Exemple : comparer chaque élément à tous les autres éléments. Double N, quadruple le travail.

Tableau de comparaison de croissance :

NO(1)O(N)O(N²)
10110100
100110010,000
1,00011,0001,000,000

À N=10, la différence semble petite. À N=1 000, l'écart devient énorme.

Comparer O(N) à O(N²)

Utilisez le tableau de comparaison de croissance ci-dessus.

À N=1 000 : O(N) nécessite 1 000 opérations. O(N²) nécessite 1 000 000 d'opérations.

À N=1 000, combien de fois plus d'opérations O(N²) nécessite-t-il par rapport à O(N) ? Montrez votre travail.

Comment la structure du code révèle la complexité

Comment identifier Big O à partir du code

Big O se cache dans la forme de votre code. Quatre modèles couvrent la plupart des cas :

Boucle unique sur N éléments : O(N)

# O(N): one pass through the list
for item in list_of_n_items:
    process(item)

Boucles imbriquées, chacune sur N éléments : O(N²)

# O(N²): every item paired with every other item
for item_a in list_of_n_items:
    for item_b in list_of_n_items:
        compare(item_a, item_b)

Recherche en temps constant : O(1)

Accès par index de tableau, recherche dans une table de hachage — une étape quel que soit la taille.

Diviser pour régner (couper le problème en deux à chaque étape) : O(log N)

Recherche binaire : chaque vérification réduit de moitié les éléments restants.

---

O(N²) caché : une liste à l'intérieur d'une boucle

# This looks like O(N) but it is actually O(N²)
visited = []
for item in list_of_n_items:
    if item not in visited:   # scans all of visited: O(N)
        visited.append(item)  # the whole loop: O(N²)

La ligne if item not in visited scanne chaque élément de visited à chaque itération. Un scan de liste coûte O(N). Une boucle qui s'exécute N fois, faisant O(N) travail chacun : O(N) × O(N) = O(N²).

Ce modèle apparaît dans 1 000+ projets open-source. La correction prend un caractère : remplacez visited = [] par visited = set(). Les tests d'appartenance à un ensemble coûtent O(1), pas O(N). Un changement. Mêmes résultats. 1 000× plus rapide à N=1 000.

Classer et corriger ce code

Lisez ce code :

result = []
for name in student_names:
    if name not in result:
        result.append(name)
Quelle est la complexité Big O de ce code ? Expliquez pourquoi la ligne `if name not in result` le rend coûteux. Ensuite, réécrivez le code pour le rendre O(N).

La théorie rencontre la pratique

Big O dans la réalité

Big O n'est pas juste une théorie. Il sépare les programmes qui se terminent en secondes des programmes qui prennent 17 minutes — sur exactement la même tâche.

Exemple réel : détection de cycle de dépendance dans un système de compilation.

Quand vous installez un logiciel, votre ordinateur résout un graphe de dépendances : le paquet A a besoin de B, B a besoin de C, et ainsi de suite. Un système de compilation vérifie ce graphe pour les cycles.

Un algorithme de détection de cycle O(N²) fonctionne bien à N=100 paquets. À N=50 000 paquets (un projet réel) : cela prend 17 minutes. La correction O(N) : 10 secondes.

Ce défaut exact existe dans GHC (compilateur Haskell), pip (gestionnaire de paquets Python), Maven (système de compilation Java), Cargo (gestionnaire de paquets Rust), & 1 000+ autres projets.

Pas parce que leurs auteurs étaient négligents. visited = [] a été écrit quand N était petit. Le code s'est calcifié. N a grandi. Personne n'a remarqué jusqu'à ce que la compilation prenne une demi-heure.

Big O est le vocabulaire qui vous permet de nommer ce qui s'est passé — & de le corriger.

---

Voulez-vous aller plus loin ? Notre cours unhamming inclut un chapitre complet sur Big O, MOAD-0001 (un vrai défaut O(N²) trouvé dans 1 000+ projets open-source), & pourquoi nommer un motif vous permet de le trouver partout. Voir The Missing Chapter: Algorithmic Complexity.

Prédire les temps de compilation

Un système de compilation utilise la détection de cycle O(N²).

Temps de compilation mesurés :

- N=100 paquets : 0,01 secondes

- N=1 000 paquets : 1 seconde

Pour O(N²) : le temps se met à l'échelle selon (N_new / N_old)².

Pour O(N) : le temps se met à l'échelle selon (N_new / N_old).

En utilisant ces formules & les données mesurées : (A) à N=10 000, combien de temps la version O(N²) prend-elle ? (B) après une correction O(N), en utilisant N=1 000 comme votre point de référence, combien de temps la version O(N) prend-elle à N=10 000 ? Montrez votre travail pour les deux.