Я обнаружил, что max
это медленнее, чем sort
функция в Python 2 и 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
Почему это max
( O(n)
) медленнее , чем sort
функции ( O(nlogn)
)?
python
sorting
max
python-internals
WeizhongTu
источник
источник
a.sort()
работает на месте. Попробуйтеsorted(a)
sort
сортирует, а потомa
сортирует навсегдаОтветы:
Вы должны быть очень осторожны при использовании
timeit
модуля в Python.python -m timeit -s 'import random;a=range(10000);random.shuffle(a)' 'a.sort();a[-1]'
Здесь код инициализации запускается один раз для создания рандомизированного массива
a
. Затем остальной код запускается несколько раз. В первый раз он сортирует массив, но каждый раз вы вызываете метод сортировки для уже отсортированного массива. Возвращается только самое быстрое время, поэтому вы фактически рассчитываете, сколько времени потребуется Python для сортировки уже отсортированного массива.Часть алгоритма сортировки Python состоит в том, чтобы определить, когда массив уже частично или полностью отсортирован. Когда он полностью отсортирован, ему просто нужно один раз просканировать массив, чтобы обнаружить это, а затем он останавливается.
Если вместо этого вы попробовали:
python -m timeit -s 'import random;a=range(100000);random.shuffle(a)' 'sorted(a)[-1]'
тогда сортировка происходит в каждом временном цикле, и вы можете видеть, что время на сортировку массива действительно намного больше, чем просто нахождение максимального значения.
Изменить: ответ @ skyking объясняет ту часть, которую я оставил необъясненной:
a.sort()
знает, что он работает со списком, поэтому может напрямую обращаться к элементам.max(a)
работает с любой произвольной итерацией, поэтому необходимо использовать общую итерацию.источник
a.sort()
знает, что работает со списком, поэтому может напрямую обращаться к элементам.max(a)
работает с произвольной последовательностью, чтобы не использовать общую итерацию.listsort.txt
объясняет: «Он обладает сверхъестественной производительностью на многих типах частично упорядоченных массивов (требуется меньше lg (N!) Сравнений и всего лишь N-1)», а затем продолжает объяснять все виды кровавой оптимизации. Я полагаю, он может делать много предположений, которыеmax
не могут, т.е. сортировка не выполняется асимптотически быстрее.Прежде всего, обратите внимание, что
max()
используется протокол итератора , аlist.sort()
используется специальный код . Очевидно, что использование итератора - это важные накладные расходы, поэтому вы наблюдаете эту разницу во времени.Однако в остальном ваши тесты нечестные. Вы участвуете
a.sort()
в одном списке более одного раза. Алгоритм , используемый Python специально разработан , чтобы быть быстро для уже (частично) сортируются данные. Ваши тесты говорят, что алгоритм хорошо выполняет свою работу.Это честные тесты:
$ 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
Здесь я каждый раз создаю копию списка. Как видите, порядок результатов отличается: микросекунды и миллисекунды, как и следовало ожидать.
И помните: big-Oh указывает верхнюю границу! Нижняя граница алгоритма сортировки Python равна Ω ( n ). Быть O ( n log n ) автоматически не означает, что каждый запуск занимает время, пропорциональное n log n . Это даже не означает, что он должен быть медленнее, чем алгоритм O ( n ), но это уже другая история. Важно понимать, что в некоторых благоприятных случаях алгоритм O ( n log n ) может работать за O ( n ) или меньше времени.
источник
Это может быть связано с тем, что
l.sort
is a member oflist
whilemax
является универсальной функцией. Это означает, чтоl.sort
можно полагаться на внутреннее представление, вlist
то время какmax
придется пройти общий протокол итератора.Это делает выборку каждого элемента
l.sort
быстрее, чем выборку каждого элементаmax
.Я предполагаю, что если вы вместо этого будете использовать,
sorted(a)
вы получите результат медленнее, чемmax(a)
.источник
sorted(a)
медленнееmax(a)
. Неудивительно, что это примерно такая же скорость, какa.sort()
, но ваше предположение относительно причины, почему нет - это потому, что OP допустил ошибку в своем тестировании, как указано в принятом ответе.log(n)
фактор сложности. То естьO(n)
алгоритм гарантированно будет быстрее, чемO(nlogn)
алгоритм для достаточно большихn
(например, потому что время для каждой операции может различаться между алгоритмами -nlogn
быстрые шаги могут быть быстрее, чемn
медленные шаги). Где именно в данном случае не учитывалось безубыточность (но следует помнить, что этотlog n
фактор не является очень большим фактором для малыхn
).