Pourquoi aucun tri ne peut battre n log n
Différents algorithmes trient les mêmes données mélangées. Chacun met de l’ordre dans le chaos à sa manière.
Lecture depuis YouTube après un clic.
Pourquoi ça marche
Mélange un jeu de cartes et trie-le en comparant deux cartes à la fois. Certaines méthodes comparent des voisines encore et encore ; d’autres coupent le jeu en deux, puis chaque moitié en deux. Sur le même mélange, les secondes finissent bien plus tôt, et aucune méthode qui ne fait que comparer ne peut faire beaucoup mieux.
comparaisons ≥ log₂(n!) ≈ n·log₂ n − 1,44·ntri à bulles : jusqu’à n·(n − 1) ÷ 2
Construis-le toi-même
Python 3 · numpy · matplotlibQuatre tris sur la même liste mélangée, avec le compte de leurs comparaisons.
"""Sorting race: four algorithms on the same shuffled list, counting their comparisons.
Run: python sorting-race.py (needs: pip install numpy matplotlib)
"""
import math
import numpy as np
import matplotlib.pyplot as plt
plt.style.use("dark_background")
n = 100
data = list(np.random.default_rng().permutation(n))
count = {"comparisons": 0}
def less(a, b): # every algorithm compares only through this, so we can count
count["comparisons"] += 1
return a < b
def bubble(xs):
xs = xs[:]
for end in range(len(xs) - 1, 0, -1):
for i in range(end):
if less(xs[i + 1], xs[i]):
xs[i], xs[i + 1] = xs[i + 1], xs[i]
return xs
def insertion(xs):
xs = xs[:]
for i in range(1, len(xs)):
j = i
while j > 0 and less(xs[j], xs[j - 1]):
xs[j], xs[j - 1] = xs[j - 1], xs[j]
j -= 1
return xs
def merge(xs):
if len(xs) < 2:
return xs
left, right = merge(xs[: len(xs) // 2]), merge(xs[len(xs) // 2 :])
out = []
while left and right:
out.append(left.pop(0) if not less(right[0], left[0]) else right.pop(0))
return out + left + right
def quick(xs):
if len(xs) < 2:
return xs
pivot, rest = xs[0], xs[1:]
smaller = [x for x in rest if less(x, pivot)]
return quick(smaller) + [pivot] + quick([x for x in rest if x not in smaller])
results = {}
for name, sort in [("bubble", bubble), ("insertion", insertion), ("merge", merge), ("quick", quick)]:
count["comparisons"] = 0
assert sort(data) == sorted(data)
results[name] = count["comparisons"]
print(results, "| at least log2(n!) =", math.ceil(math.log2(math.factorial(n))))
plt.figure(figsize=(7, 4))
plt.bar(list(results), list(results.values()), color=["#f0abfc", "#c4b5fd", "#5eead4", "#5eead4"])
plt.axhline(math.log2(math.factorial(n)), color="white", linestyle="--", label="log2(n!): no comparison sort does better")
plt.ylabel(f"comparisons for n = {n}")
plt.legend()
plt.show()
# Try: n = 1000 (bubble sort needs about n*n/2, merge sort about n*log2(n))
Essaie : Mets n = 1000 : le compte du tri à bulles est multiplié par cent environ, celui du tri fusion par seize environ.
Apprends ce script ligne par ligne, avec des exercices et un quiz → · lance-le dans Google Colab (en anglais) →