Цена естественности или как обогнать QuickSort
Запись от Catstail размещена 03.11.2020 в 22:19
Показов 4325
Комментарии 6
|
Сортировка — такая же «вечная» тема для алгоритмистов, как любовь — для поэтов. Казалось бы, новое слово в этой области сказать трудно, а поди же ты — продолжают придумывать новые алгоритмы сортировок (TimSort...) Есть, однако, базовые факты, которые знает каждый приличный студент. Известно, к примеру, что универсальный алгоритм сортировки не может быть быстрее O(n*log(n)). Такой показатель производительности имеет знаменитая QuckSort (придуманная в 1960-м году Хоаром), а также сортировка слиянием (Фон Неймана) и пирамидальная сортировка. Что же касается элементарных алгоритмов («пузырек», «вставки», «выбор»), то их показатель существенно хуже — O(n^2). Но всегда ли QuickSort является «абсолютным чемпионом»? Ведь кроме показателя производительности есть и другие характеристики, зачастую — не менее важные. Один из них — естественность. Что это такое? Сортировка называется естественной, если она выполняется быстрее в том случае, когда массив уже почти отсортирован. А какой массив можно считать «почти отсортированным»? Вот два массива, состоящие из одних и тех элементов: {1,2,9,3,4,5,7,6,8,10} и {9,1,6,3,10,5,4,2,8,7} Даже на глаз видно, что первый массив более упорядочен (только 9 и 7 стоят «не на месте»). Тогда как во втором массиве числа перемешаны хаотически. Что же является мерой упорядоченности? Ответ известен — количество инверсий. Пара элементов A[i] и A[j] при j > i составляют инверсию, если A[j] < A[i]. (В этой заметке целью сортировки всегда является упорядочение по возрастанию). Теперь можно дать точное определение: сортировка называется естественной, если время ее работы снижается при снижении количества инверсий в исходном массиве. Естественность — достаточно «редкий фрукт» в мире сортировок — ни QuickSort ни сортировка Шелла не обладают этим свойством, увы. Но есть один алгоритм, который, можно сказать, является абсолютно естественным — это сортировка вставками. Хотя этот алгоритм известен каждому культурному человеку, позволю себе кратко повторить его суть. Сортируемый массив просматривается один раз от начала к концу. Как только обнаруживается, что i-й и (i-1)-элементы образуют инверсию, i-й элемент «закидывается» назад (что достигается сдвигом нужного отрезка начала массива вправо на одну позицию). Из этого описания понятно, что если в массиве мало инверсий, алгоритм «пролетит» по массиву очень быстро. Если инверсий нет совсем, то алгоритм завершится за время O(n). А вот QuickSort в этом случае будет долго и утомительно выбирать разделяющий элемент, делить уже упорядоченный массив на отрезки и т.п. Но при наличии большого количества инверсий ситуация, разумеется, будет обратной: производительность сортировки вставками упадет до O(n^2), а QuickSort будет чемпионом — O(n*log(n)). Сложившаяся ситуация порождает естественный с моей точки зрения вопрос: при каком количестве инверсий перевешивает естественность и сортировка вставками работает быстрее QuickSort? Для ответа на этот вопрос я провел серию вычислительных экспериментов. Суть их состояла в следующем. Брались массивы целых чисел размером от 3000 до 30000 элементов, в них вносилось некоторое количество инверсий, затем массивы сортировались вставками и быстрой сортировкой. Замерялось время сортировки (в системных тиках). Для усреднения каждая сортировка повторялась 10 раз. Результаты оказались следующими: На картинке представлены зависимости времени сортировки от количества внесенных инверсий. Малиновая серия - это, естественно, QuickSort, а синяя - сортировка вставками. Для размера массива 30 тыс. элементов, до примерно 400 тыс. инверсий "побеждает естественность". Для менее упорядоченных массивов уже выгоднее QuickSort. А на следующей картинке приведена эмпирическая зависимость критического количества инверсий от размера массива. Легко видеть, что для массива размера n критическое количество инверсий составляет примерно 10*n. При большем количестве инверсий выгоден QuickSort. Следует отметить, что максимальное количество инверсий для массива длины n составляет n*(n-1)/2. Величина 10*n есть весьма незначительная их часть. Что и неудивительно. К сказанному осталось добавить, что результаты таких экспериментов зависят от многих факторов (языка программирования, типа сортируемых данных и т.п.) Мне, честно говоря, было лень исследовать эти вопросы более детально. Мои эксперименты проводились в Microsoft Excel в среде VBA:
ссылка на хабре | |||||
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 6
Комментарии
-
С удовольствием прочел, у вас определенно талант к изложению, отдельное спасибо за "этот алгоритм известен каждому культурному человеку"
Ссылку не верно дали,это ваша авторская, надо вот такую

Запись от Welemir1 размещена 04.11.2020 в 10:03
-
Запись от Catstail размещена 04.11.2020 в 15:23
-
Применение правильного алгоритма, иногда, единственный способ решить вопрос со скоростью вычислений.
Просматривал тематику алгоритмов сортировки, Ваша статья оказалась кстати, спасибо за более
подробную информацию при освоении алгоритмов и структур данных.Запись от AlexMarkov размещена 19.03.2021 в 17:39
-
Запись от CoderHuligan размещена 19.03.2021 в 19:11
-
Запись от Catstail размещена 11.04.2021 в 15:33
-
Запись от Catstail размещена 11.04.2021 в 15:34



