Leçon
La théorie — Explorateur de complexité Big-O
Le grand O est une borne supérieure de croissance, et non une mesure du temps. Dire qu’un algorithme est O(N²) signifie qu’au-delà d’une certaine taille d’entrée, son travail reste inférieur à un multiple fixe de N² — cela ne dit rien sur les secondes, et absolument rien sur les petites entrées.
Ce que signifie chaque symbole
N- la taille de l’entrée — le nombre d’éléments fournis à l’algorithme. C’est le nombre réglé ci-dessus, allant de 2 à 1 000 000.
f(N)- le travail réellement effectué pour cette taille, compté en opérations abstraites plutôt qu’en secondes.
c- un facteur multiplicatif constant que la notation a le droit de masquer. L’affirmation est
f(N) ≤ c·g(N); c peut valoir 2 ou 2 000, et c’est précisément cette information que le grand O ignore. n₀- la taille au-delà de laquelle la borne doit s’appliquer. En dessous de
n₀, les classes peuvent se ranger dans n’importe quel ordre, c’est pourquoi les cinq nombres ci-dessus se regroupent pour les petites valeurs de N.
D’où vient la formule
- Partons de l’affirmation à rendre précise : le travail
f(N)finit par ne pas croître plus vite qu’une fonction de référenceg(N). - “Ne pas croître plus vite” doit tolérer un facteur constant, car l’optimisation d’une boucle interne modifie la constante, pas la forme de la courbe. On autorise donc un multiplicateur :
f(N) ≤ c·g(N). - Et “à terme” doit tolérer les petites entrées, où tout peut arriver. On n’impose l’inégalité qu’une fois
N ≥ n₀. En résumé :f(N) = O(g(N))signifie qu’il existe unc > 0et unn₀tels quef(N) ≤ c·g(N)pour toutN ≥ n₀.
Comment lire ce que vous voyez
Les cinq lignes représentent une même taille d’entrée évaluée dans cinq classes de croissance avec toutes les constantes fixées à 1 — ce sont donc des comptes d’opérations, pas des temps d’exécution. Avec la valeur par défaut N = 100, elles indiquent 1, 7, 100, 664 et 10,000. Le logarithme est en base 2 : log₂ 100 ≈ 6.64, c’est pourquoi O(log N) affiche 7 et O(N log N) affiche 664 au lieu de 700.
- Suppose
- Que chaque opération a le même coût que n’importe quelle autre, et que le décompte est exact plutôt que mesuré. C’est ce qui rend la comparaison nette, et tout autant ce qui la rend abstraite — les profils d’accès à la mémoire, le comportement du cache et le disque sont tous exclus de ce modèle, et sur un matériel réel, ce sont eux qui déterminent couramment quel algorithme l’emporte.
- Ne tient plus quand
- La borne ne garantit rien en dessous de
n₀, et vous pouvez l’observer directement : réglezN = 2et les cinq classes indiquent1,1,2,2et4— quasiment indistinctement. L’ordre garanti par la notation n’émerge que lorsque N devient grand, ce qui explique pourquoi une méthode enO(N²)avec une petite constante peut surpasser une méthode enO(N log N)pour n’importe quelle entrée que vous manipulerez en pratique.
Problème entièrement résolu
-
Où le gouffre se creuse entre N log N et N ² 5 étapes
À N = 100, le panneau affiche 664 pour N log N et 10 000 pour N². Cela ne représente qu'un facteur de quinze — loin du gouffre que les classes de complexité sont censées représenter. Déterminez où ce gouffre s'ouvre réellement.
-
Commencez par les deux nombres. log₂ 100 vaut 6,6439, donc N log₂ N vaut 664 et N² vaut 10 000.
-
Le ratio entre eux n'est pas une constante, et c'est tout l'intérêt des classes de complexité. Divisez et le N s'annule une fois, laissant N/log N — une quantité qui croît sans borne, simplement lentement.
-
À N = 100, il est de 15,1. C'est réel mais peu impressionnant : un gain d'un facteur quinze est le genre de chose qu'un meilleur facteur constant pourrait vous apporter, ce qui explique exactement pourquoi les tests de performance sur de petites entrées induisent en erreur.
-
Injectez maintenant un million. Le logarithme a à peine bougé — de 6,6 à 19,9, un facteur de trois — tandis que N a été multiplié par dix mille. Le ratio est désormais de 50 172.
-
Et il ne s'inverse jamais. La dérivée de N/log N est positive pour tout N supérieur à e, il n'existe donc aucune taille d'entrée au-delà de laquelle l'algorithme quadratique rattrape son retard.
Réponse
L'outil affiche 664 contre 10 000 pour N = 100. Le nombre qui mérite d'être retenu est l'autre : à un million, ces deux mêmes courbes sont séparées de 50 172. Les classes de complexité ne traitent pas de paquets de cent éléments, et les comparer à cette échelle est le moyen classique de se convaincre d'opter pour le mauvais algorithme — un écart d'un facteur quinze ressemble à ce qu'un langage plus rapide pourrait combler. Déplacez le curseur vers le haut et observez le ratio augmenter. C'est également la raison pour laquelle le logarithme est si souvent négligé en pratique : il n'a augmenté que d'un facteur trois alors que l'entrée a été multipliée par dix mille.
-
Parcours
Compter le travail, pas les secondes
Références (1)
- The definition the lesson states, and the case for using it carefully: D. E. Knuth, “Big Omicron and big Omega and big Theta.” ACM SIGACT News 8, 18–24, 1976.