J'ai trouvé que max
c'est plus lent que la sort
fonction en Python 2 et 3.
Python 2
$ python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]'
1000 loops, best of 3: 239 usec per loop
$ python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'max(a)'
1000 loops, best of 3: 342 usec per loop
Python 3
$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'a.sort();a[-1]'
1000 loops, best of 3: 252 usec per loop
$ python3 -m timeit -s 'import random;a=list(range(10000));random.shuffle(a)' 'max(a)'
1000 loops, best of 3: 371 usec per loop
Pourquoi est max
( O(n)
) plus lente que la sort
fonction ( O(nlogn)
)?
python
sorting
max
python-internals
WeizhongTu
la source
la source
a.sort()
fonctionne en place. Essayezsorted(a)
sort
trie, puisa
est trié pour toujoursRéponses:
Vous devez être très prudent lorsque vous utilisez le
timeit
module en Python.Ici, le code d'initialisation s'exécute une fois pour produire un tableau aléatoire
a
. Ensuite, le reste du code est exécuté plusieurs fois. La première fois, il trie le tableau, mais chaque fois que vous appelez la méthode de tri sur un tableau déjà trié. Seul le temps le plus rapide est renvoyé, vous chronométrez donc en fait le temps qu'il faut à Python pour trier un tableau déjà trié.Une partie de l'algorithme de tri de Python consiste à détecter lorsque le tableau est déjà partiellement ou complètement trié. Une fois complètement trié, il doit simplement balayer une fois la matrice pour le détecter, puis il s'arrête.
Si à la place vous avez essayé:
puis le tri se produit sur chaque boucle de synchronisation et vous pouvez voir que le temps de tri d'un tableau est en effet beaucoup plus long que de simplement trouver la valeur maximale.
Edit: la réponse de @ skyking explique la partie que j'ai laissée inexpliquée:
a.sort()
sait qu'elle travaille sur une liste et peut donc accéder directement aux éléments.max(a)
fonctionne sur toute itération arbitraire doit donc utiliser une itération générique.la source
a.sort()
sait qu'il travaille sur une liste et peut donc accéder directement aux éléments.max(a)
fonctionne sur une séquence arbitraire pour ne pas utiliser une itération générique.listsort.txt
explique "Il a des performances surnaturelles sur de nombreux types de tableaux partiellement ordonnés (moins de comparaisons lg (N!) Nécessaires, et aussi peu que N-1)" et continue ensuite à expliquer toutes sortes d'optimisations sanglantes. Je suppose qu'il peut faire beaucoup d'hypothèses quimax
ne le peuvent pas, c'est-à-dire que le tri n'est pas asymptotiquement plus rapide.Tout d'abord, notez qu'il
max()
utilise le protocole itérateur , tout enlist.sort()
utilisant un code ad hoc . De toute évidence, l'utilisation d'un itérateur est une surcharge importante, c'est pourquoi vous observez cette différence de temps.Cependant, à part cela, vos tests ne sont pas équitables. Vous exécutez
a.sort()
plusieurs fois sur la même liste. L' algorithme utilisé par Python est spécifiquement conçu pour être rapide pour les données déjà (partiellement) triées. Vos tests indiquent que l'algorithme fait bien son travail.Ce sont des tests équitables:
Ici, je crée une copie de la liste à chaque fois. Comme vous pouvez le voir, l'ordre de grandeur des résultats est différent: micro- vs millisecondes, comme on pouvait s'y attendre.
Et rappelez-vous: big-Oh spécifie une limite supérieure! La limite inférieure de l'algorithme de tri de Python est Ω ( n ). Être O ( n log n ) n'implique pas automatiquement que chaque exécution prend un temps proportionnel à n log n . Cela n'implique même pas qu'il doit être plus lent qu'un algorithme O ( n ), mais c'est une autre histoire. Ce qu'il est important de comprendre, c'est que dans certains cas favorables, un algorithme O ( n log n ) peut s'exécuter en un temps O ( n ) ou moins.
la source
Cela peut être dû au
l.sort
fait que est membre delist
whilemax
est une fonction générique. Cela signifie quel.sort
peut s'appuyer sur la représentation interne delist
whilemax
devra passer par le protocole générique d'itérateur.Cela fait que chaque élément recherché
l.sort
est plus rapide que chaque élément extrait quemax
fait.Je suppose que si vous utilisez à la place,
sorted(a)
vous obtiendrez le résultat plus lentement quemax(a)
.la source
sorted(a)
plus lent quemax(a)
. Sans surprise, c'est à peu près la même vitesse quea.sort()
, mais votre conjecture quant à la raison ne l'est pas - c'est parce que l'OP a commis une erreur dans ses tests, comme indiqué dans la réponse acceptée.log(n)
facteur de complexité. C'est-à-dire qu'unO(n)
algorithme n'est garanti que plus rapide qu'unO(nlogn)
algorithme pour suffisamment grandn
(par exemple parce que le temps de chaque opération peut différer entre les algorithmes -nlogn
les étapes rapides peuvent être plus rapides quen
les étapes lentes). L'endroit exact où le seuil de rentabilité n'est pas pris en compte dans ce cas (mais il faut être conscient que lelog n
facteur n'est pas un facteur très important pour les petitsn
).