При выборе алгоритма часто говорят об асимптотике того или иного решения задачи. При этом можно встретить высказывания, что, мол, «вот этот» алгоритм работает за O(n), а «вон тот» – за O(n·log(n)), значит первый однозначно лучше. Либо раз оба метода работают за O(n²), значит их можно считать равнозначными, и обсуждать, чем один может быть лучше другого, большого смысла нет. Лично я не могу согласиться с таким мнением, по крайней мере, когда речь идёт в контексте программирования, поэтому решил написать данную статью и поделиться некоторыми мыслями о возможных нюансах. Если подумать ещё, наверняка можно найти и другие нюансы, но по-моему, и этого уже достаточно, чтобы хорошенько задуматься: действительно ли «O» – единственный важный показатель скорости алгоритма? Неужели разница в скорости в 2, 5, 10 раз ничего не значит? Почему же большинство людей предпочитают быстрые SSD, нежели медленные HDD? Ведь алгоритмы копирования везде одинаковые (по крайней мере, лично я больше чем O(n) пока не встречал) :) А представьте, какова может быть разница, если просуммировать все эти нюансы! Некоторые алгоритмы с бóльшим «O» могут работать чуть быстрее, чем иные с меньшим «O» (по меньшей мере, для относительно небольших n… кстати, а всегда ли n должно стремиться к бесконечности при оценке скорости алгоритма?) В качестве конкретного примера приведу методы сортировки массивов. Многие думают, что методы сортировки пузырьком и вставками примерно одинаковы по скорости (поскольку сложность обоих составляет O(n²)). Однако я не раз убеждался на практике, что сортировка вставками работает почти на порядок быстрее. Для иллюстрации этого некоторое время назад я сделал небольшой сравнительный тест нескольких методов сортировки (ниже в комментариях выложены результаты теста на моём компьютере, соотношение скорости сортировки пузырьком и вставками указано в строке «Bubble/insertion sort time ratio»). Кроме того, алгоритм быстрой сортировки (который тоже имеет множество реализаций, ощутимо различающихся как по скорости, так и по глубине рекурсии) может модифицироваться таким образом, что при достижении некоторого порога размера массивов, на которые происходит деление исходного массива (например, когда элементов становится меньше 16-ти; а иногда ещё и при достижении определённой глубины рекурсии), сортировка переключается на… сортировку вставками (либо дальнейшая быстрая сортировка прекращается, а сортировка вставками применяется уже позже ко всему не до конца отсортированному массиву). Казалось бы, зачем это делается, ведь сортировка вставками значительно медленнее быстрой сортировки? Однако на практике оказывается, что сортировка небольших массивов зачастую происходит чуть быстрее именно «вставками», нежели «быстрым» методом («quick/quick-insertion sort time ratio» в том же тесте по ссылке выше). Даже в тех случаях, когда скорость обоих методом примерно равная, глубина рекурсии уменьшается. Какой вывод можно сделать из всего этого? Очень простой: теория – это хорошо, но она должна подкрепляться практикой и знаниями возможных подводных камней. Как гласит японская пословица, знание является наградой за действие. Хочу поблагодарить читателей за проявленный интерес к статье, особенно тех, кто поделился своими мыслями в комментариях. Это моя первая статья на Хабре, и для меня это ценно. Именно после прочтения ваших сообщений я решил добавить этот эпилог. Разумеется, при бесконечно больших объёмах данных (n → ∞) асимптотическая оценка сложности будет как нельзя лучше отражать характер роста времени работы алгоритмов. И никакие доводы, что "сложение быстрее деления" или что "константа всё же имеет значение" не будут столь важны, как эта оценка. Однако в реальной жизни не все так идеально, как в математике, и объём данных почти всегда ограничен (причём, нередко довольно небольшими величинами). А это значит, что есть смысл брать во внимание и другие параметры и оценить реальную эффективность с учётом этих параметров и возможных диапазонов величины n. Но и здесь важно трезво смотреть на ситуацию: не вырастет ли "завтра" это n на порядок, к примеру, в связи с технологическим ростом или ростом бизнеса? Может быть, действительно есть смысл использовать алгоритм, который сейчас работает в 1.5 раза медленнее, но через месяц окажется в 2 раза быстрее, а через год – в 5? Или даже сделать 2 алгоритма и динамически выбирать между ними в зависимости от объёма входных данных! По этому поводу мне вспомнилась история с катастрофой на Ariane 5. Вряд ли будет открытием, что к любому делу нужно подходить с умом. Асимптотика придумана умными людьми, и она важна. Провести замер скорости без учёта асимптотики будет тоже не очень разумно. Но чтобы "уехать далеко", лучше иметь два колеса, а не одно. А ещё лучше – четыре. Нужно учитывать сразу несколько параметров. И помнить о приоритетах. Где-то наиболее важным будет скорость работы алгоритма, где-то объём используемой памяти, где-то это всё будет вообще несущественным (ввиду малых значений), а гораздо важнее написать функцию быстро. И т.д. Ключевые идеи статьи: Программист, вокалист, ивентор, хороший человек