Odkryłem, że max
jest wolniejszy niż sort
funkcja w Pythonie 2 i 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
Dlaczego jest max
( O(n)
) wolniej niż sort
funkcja ( O(nlogn)
)?
python
sorting
max
python-internals
WeizhongTu
źródło
źródło
a.sort()
działa w miejscu. Spróbujsorted(a)
sort
sortuje, a następniea
jest sortowane na zawszeOdpowiedzi:
Musisz być bardzo ostrożny używając
timeit
modułu w Pythonie.python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]'
Tutaj kod inicjalizacyjny jest uruchamiany raz, aby utworzyć losową tablicę
a
. Następnie reszta kodu jest uruchamiana kilka razy. Za pierwszym razem sortuje tablicę, ale za każdym razem, gdy wywołujesz metodę sort na już posortowanej tablicy. Zwracany jest tylko najszybszy czas, więc tak naprawdę odliczasz, ile czasu zajmie Pythonowi posortowanie już posortowanej tablicy.Częścią algorytmu sortowania Pythona jest wykrywanie, kiedy tablica jest już częściowo lub całkowicie posortowana. Po całkowitym posortowaniu musi po prostu raz przeskanować macierz, aby to wykryć, a następnie zatrzymuje się.
Jeśli zamiast tego próbowałeś:
python -m timeit -s 'import random;a=range(100000);random.shuffle(a)' 'sorted(a)[-1]'
wtedy sortowanie odbywa się w każdej pętli czasowej i widać, że czas na sortowanie tablicy jest rzeczywiście znacznie dłuższy niż znalezienie maksymalnej wartości.
Edit: @ skyking na odpowiedź wyjaśnia część zostawiłem niewyjaśnione:
a.sort()
wie, że pracuje na liście, więc można bezpośrednio uzyskać dostęp do elementów.max(a)
działa na dowolnej dowolnej iteracji, więc musi używać ogólnej iteracji.źródło
a.sort()
wie, że pracuje na liście, więc ma bezpośredni dostęp do elementów.max(a)
działa na dowolnej sekwencji, aby nie używać ogólnej iteracji.listsort.txt
wyjaśnia „Ma nadprzyrodzoną wydajność na wielu rodzajach częściowo uporządkowanych tablic (potrzeba mniej niż lg (N!) Porównań i tylko N-1)”, a następnie wyjaśnia wszystkie rodzaje krwawych optymalizacji. Przypuszczam, że może dokonać wielu założeń, którychmax
nie może, czyli sortowanie nie jest asymptotycznie szybsze.Po pierwsze, należy zauważyć, że
max()
używa protokołu iteratora , podczas gdylist.sort()
używa kodu ad-hoc . Oczywiście używanie iteratora jest ważnym narzutem, dlatego obserwujesz tę różnicę w czasie.Jednak poza tym twoje testy nie są sprawiedliwe. Jesteś
a.sort()
na tej samej liście więcej niż raz. Algorytm Python jest zaprojektowana jako szybka już (częściowo) posortowane dane. Twoje testy wskazują, że algorytm dobrze wykonuje swoją pracę.To są uczciwe testy:
$ 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
Tutaj za każdym razem tworzę kopię listy. Jak widać, rząd wielkości wyników jest inny: mikro- vs milisekundy, tak jak byśmy się spodziewali.
I pamiętaj: big-Oh określa górną granicę! Dolna granica algorytmu sortowania Pythona to Ω ( n ). Bycie O ( n log n ) nie oznacza automatycznie, że każdy przebieg zajmuje czas proporcjonalny do n log n . Nie oznacza to nawet, że musi być wolniejszy niż algorytm O ( n ), ale to już inna historia. Ważne jest, aby zrozumieć, że w niektórych korzystnych przypadkach algorytm O ( n log n ) może działać w czasie O ( n ) lub krótszym.
źródło
Może to być spowodowane tym, że
l.sort
element członkowskilist
whilemax
jest funkcją ogólną. Oznacza to, żel.sort
może polegać na wewnętrznej reprezentacjilist
whilemax
będzie musiał przejść przez ogólny protokół iteratora.To sprawia, że każdy element pobiera
l.sort
szybciej niż każdy element, który tomax
robi.Zakładam, że jeśli zamiast tego użyjesz
sorted(a)
, uzyskasz wynik wolniej niżmax(a)
.źródło
sorted(a)
to jest wolniejsze niżmax(a)
. Nic dziwnego, że jest to mniej więcej taka sama prędkość, jaka.sort()
, ale twoje przypuszczenie, dlaczego tak nie jest - to dlatego, że OP popełnił błąd podczas testów, jak wskazano w zaakceptowanej odpowiedzi.log(n)
czynnik złożoności. Oznacza to, żeO(n)
algorytm ma gwarancję, że będzie szybszy niżO(nlogn)
algorytm dla wystarczająco dużychn
(na przykład dlatego, że czas każdej operacji może się różnić między algorytmami -nlogn
szybkie kroki mogą być szybsze niżn
wolne). Dokładnie tam, gdzie próg rentowności nie jest brany pod uwagę w tym przypadku (ale należy mieć świadomość, żelog n
współczynnik nie jest bardzo dużym czynnikiem dla małychn
).