sort lista python sorting max python-internals

python - lista - ¿Por qué es max más lento que el tipo?



sort python 3 (3)

En primer lugar, tenga en cuenta que max() usa el protocolo iterador , mientras que list.sort() usa código ad-hoc . Claramente, el uso de un iterador es una sobrecarga importante, es por eso que está observando esa diferencia en los tiempos.

Sin embargo, aparte de eso, sus pruebas no son justas. Está ejecutando a.sort() en la misma lista más de una vez. El algoritmo utilizado por Python está específicamente diseñado para ser rápido para datos ya (parcialmente) ordenados. Sus pruebas dicen que el algoritmo está haciendo bien su trabajo.

Estas son pruebas justas:

$ python3 -m timeit -s ''import random;a=list(range(10000));random.shuffle(a)'' ''max(a[:])'' 1000 loops, best of 3: 227 usec per loop $ python3 -m timeit -s ''import random;a=list(range(10000));random.shuffle(a)'' ''a[:].sort()'' 100 loops, best of 3: 2.28 msec per loop

Aquí estoy creando una copia de la lista cada vez. Como puede ver, el orden de magnitud de los resultados es diferente: micro y milisegundos, como era de esperar.

Y recuerde: big-Oh especifica un límite superior! El límite inferior para el algoritmo de clasificación de Python es Ω ( n ). Ser O ( n log n ) no implica automáticamente que cada ejecución tome un tiempo proporcional a n log n . Ni siquiera implica que deba ser más lento que un algoritmo O ( n ), pero esa es otra historia. Lo importante es entender que en algunos casos favorables, un algoritmo O ( n log n ) puede ejecutarse en tiempo O ( n ) o menos.

Descubrí que max es más lento que la función de sort en Python 2 y 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

¿Por qué max ( O(n) ) es más lento que la función de sort ( O(nlogn) )?


Esto podría deberse a que l.sort es miembro de la list mientras que max es una función genérica. Esto significa que l.sort puede confiar en la representación interna de la list mientras que max tendrá que pasar por un protocolo iterador genérico.

Esto hace que cada recuperación de elementos para l.sort sea ​​más rápida que la recuperación de cada elemento que hace max .

Supongo que si en su lugar usa sorted(a) obtendrá el resultado más lento que max(a) .


timeit tener mucho cuidado al usar el módulo timeit en Python.

python -m timeit -s ''import random;a=range(10000);random.shuffle(a)'' ''a.sort();a[-1]''

Aquí el código de inicialización se ejecuta una vez para producir una matriz aleatoria a . Luego, el resto del código se ejecuta varias veces. La primera vez que ordena la matriz, pero cada dos veces está llamando al método de ordenación en una matriz ya ordenada. Solo se devuelve el tiempo más rápido, por lo que en realidad está cronometrando cuánto tiempo le lleva a Python ordenar una matriz ya ordenada.

Parte del algoritmo de clasificación de Python es detectar cuándo la matriz ya está parcial o completamente clasificada. Cuando está completamente ordenado, simplemente tiene que escanear una vez a través de la matriz para detectar esto y luego se detiene.

Si en cambio lo intentaste:

python -m timeit -s ''import random;a=range(100000);random.shuffle(a)'' ''sorted(a)[-1]''

entonces la ordenación ocurre en cada ciclo de tiempo y puede ver que el tiempo para ordenar una matriz es mucho más largo que solo encontrar el valor máximo.

Editar: la answer @ skyking explica la parte que dejé sin explicar: a.sort() sabe que está trabajando en una lista, por lo que puede acceder directamente a los elementos. max(a) funciona en cualquier iterativo arbitrario, por lo que debe usar iteración genérica.