Jump to content

Флэш-сортировка

Flashsort — это алгоритм сортировки по распределению, показывающий линейную вычислительную сложность O ( n ) для равномерно распределенных наборов данных и относительно небольшое требование к дополнительной памяти. Оригинальная работа была опубликована в 1998 году Карлом-Дитрихом Нойбертом. [1]

Концепция

[ редактировать ]

Flashsort — это эффективная на месте реализация сортировки гистограмм , которая сама по себе является разновидностью сортировки по сегментам . Он присваивает каждый из n входных элементов одному из m сегментов , эффективно переупорядочивает входные данные, чтобы расположить сегменты в правильном порядке, а затем сортирует каждый сегмент. Исходный алгоритм сортирует входной массив A следующим образом:

  1. Используя первый проход по входным данным или априорным знаниям, найдите минимальный и максимальный ключи сортировки.
  2. Линейно разделите диапазон [ A min , A max ] на m сегментов.
  3. Сделайте один проход по входным данным, подсчитав количество элементов A i, попавших в каждое ведро. (Нойберт называет сегменты «классами», а присвоение элементов их сегментам — «классификацией».)
  4. Преобразуйте количество элементов в каждом сегменте в префиксную сумму , где L b — количество элементов A i в сегменте b или меньше. ( L 0 знак равно 0 и L м знак равно п .)
  5. Переставьте входные данные так, чтобы все элементы каждого сегмента b сохранялись в позициях A i, где L b −1 < i L b .
  6. Отсортируйте каждую корзину, используя сортировку вставками .

Шаги 1–3 и 6 являются общими для любой сортировки по сегментам и могут быть улучшены с использованием методов, общих для сортировок по сегментам. В частности, цель состоит в том, чтобы сегменты были примерно одинакового размера ( n / m элементов), каждое [1] идеалом является деление на m квантилей . Хотя базовый алгоритм представляет собой сортировку с линейной интерполяцией , если известно, что входное распределение неравномерно, нелинейное деление будет более точно приближаться к этому идеалу. Аналогично, при окончательной сортировке можно использовать любой из множества методов, включая рекурсивную флэш-сортировку.

Что отличает флэш-сортировку, так это шаг 5: эффективный алгоритм O ( n ) на месте для сбора элементов каждого сегмента вместе в правильном относительном порядке, используя только m слов дополнительной памяти.

Эффективная реализация памяти

[ редактировать ]

Фаза переупорядочивания Flashsort выполняется циклично . Элементы сначала «неклассифицируются», затем перемещаются в нужную корзину и считаются «классифицированными». Основная процедура состоит в том, чтобы выбрать неклассифицированный элемент, найти его правильную корзину, заменить его там неклассифицированным элементом (который должен существовать, поскольку мы заранее подсчитали размер каждой корзины), пометить его как классифицированный, а затем повторить действия с только что обмененный неклассифицированный элемент. В конце концов элемент обменивается сам с собой, и цикл завершается.

Детали легко понять, используя две переменные (размером в слово) на сегмент. Хитрость заключается в исключении одной из этих переменных, что позволяет использовать вдвое больше сегментов и, следовательно, вдвое меньше времени, затрачиваемого на окончательный результат O ( n 2 ) сортировка.

Чтобы понять это с двумя переменными на ведро, предположим, что есть два массива из m дополнительных слов: K b — это (фиксированный) верхний предел ведра b K 0 = 0 ), а L b — это (перемещаемый) индекс в ведре. b , поэтому K b −1 L b K b .

Мы поддерживаем инвариант цикла , согласно которому каждый сегмент делится на L b на неклассифицированный префикс ( A i для K b −1 < i L b еще не перемещен в целевые сегменты) и классифицированный суффикс ( A i для L b < i K b все находятся в правильном сегменте и больше не будут перемещены). Первоначально L b = K b и все элементы неклассифицированы. По мере сортировки L b уменьшаются до тех пор, пока L b = K b -1 для всех b , и все элементы не будут классифицированы в правильную корзину.

Каждый раунд начинается с поиска первого не полностью классифицированного сегмента c (который имеет K c −1 < L c ) и взятия первого неклассифицированного элемента в этом блоке A i, где i = K c −1 + 1 . (Нойберт называет это «лидером цикла».) Скопируйте A i во временную переменную t и повторите:

  • Вычислите сегмент b, которому принадлежит t .
  • Пусть j = L b — место, где t . будет храниться
  • Обменяйте t на Aj извлекая , т.е. сохраните t в Aj , при этом предыдущее значение Aj , смещенное таким образом.
  • Уменьшите L b , чтобы отразить тот факт, что A j теперь правильно классифицирован.
  • Если j i , перезапустите этот цикл с новым t .
  • Если j = i , этот раунд завершается и начинается поиск нового первого неклассифицированного элемента A i .
  • Когда неклассифицированных элементов больше нет, распределение по сегментам завершено.

При такой реализации с двумя переменными на сегмент выбор начальной точки i каждого раунда фактически является произвольным; любой неклассифицированный элемент может использоваться в качестве лидера цикла. Единственное требование – чтобы можно было эффективно найти лидеров цикла.

Хотя в предыдущем описании для поиска лидеров цикла используется K , на самом деле можно обойтись и без него, позволяя m исключить весь массив -слов. (После завершения распределения границы сегмента можно найти в L. )

Предположим, что мы классифицировали все элементы до i −1 и рассматриваем A i как потенциального нового лидера цикла. легко вычислить Целевой сегмент b . По инварианту цикла он классифицируется, если L b < i K b , и неклассифицируется, если i находится за пределами этого диапазона. Первое неравенство легко проверить, но второе, по-видимому, требует значения K b .

Оказывается, из предположения индукции о том, что все элементы до i −1 классифицируются, следует, что i K b , поэтому проверять второе неравенство нет необходимости.

Рассмотрим ведро c, в позицию которого i попадает . То есть K c −1 < i K c . По предположению индукции все элементы ниже i , включая все сегменты до K c −1 < i , полностью классифицированы. Т.е. никакие элементы, принадлежащие этим сегментам, не остаются в остальной части массива. Следовательно, невозможно, чтобы b < c .

Остается только случай b c , из которого следует, что K b K c i , QED

Учитывая это, алгоритм распределения flashsort начинается с L, как описано выше, и i = 1 . Затем продолжайте: [1] [2]

  • Если i > n , распределение полное.
  • Учитывая A i , вычислите сегмент b, которому он принадлежит.
  • Если i L b , то A i неклассифицирован. Скопируйте временную переменную t и:
    • Пусть j = L b — место, где t . будет храниться
    • Обменяйте t на Aj извлекая , т.е. сохраните t в Aj , при этом предыдущее значение Aj , смещенное таким образом.
    • Уменьшите L b , чтобы отразить тот факт, что A j теперь правильно классифицирован.
    • Если j i , вычислите сегмент b , которому принадлежит t, и перезапустите этот (внутренний) цикл с новым t .
  • A i теперь правильно классифицировано. Увеличьте i и перезапустите (внешний) цикл.

Несмотря на экономию памяти, Flashsort имеет тот недостаток, что она пересчитывает сегмент для многих уже классифицированных элементов. Это уже делается дважды для каждого элемента (один раз на этапе подсчета сегментов и второй раз при перемещении каждого элемента), но поиск первого неклассифицированного элемента требует третьего вычисления для большинства элементов. Это может оказаться дорогостоящим, если сегменты назначаются с использованием более сложной формулы, чем простая линейная интерполяция. Вариант уменьшает количество вычислений почти с 3 n до максимум 2 n + m − 1, беря последний неклассифицированный элемент в незавершенной корзине в качестве лидера цикла:

  • Сохраните переменную c, идентифицирующую первую не полностью классифицированную корзину. Пусть c = 1 для начала , а когда c > m , распределение является полным.
  • Пусть я = Lc . Если i = L c −1 , увеличьте c и перезапустите этот цикл. ( Л 0 знак равно 0 .)
  • Вычислите сегмент b, которому принадлежит A i .
  • Если b < c , то L c = K c −1 , и мы закончили с ведром c . Увеличьте c и перезапустите этот цикл.
  • Если b = c , классификация тривиальна. Уменьшите L c и перезапустите этот цикл.
  • Если b > c , то A i неклассифицирован. Выполните тот же цикл классификации, что и в предыдущем случае, а затем перезапустите этот цикл.

Для большинства элементов сегменты вычисляются только дважды, за исключением последнего элемента в каждом сегменте, который используется для определения завершения следующего сегмента. Небольшого дальнейшего сокращения можно добиться, сохраняя количество неклассифицированных элементов и останавливая его, когда оно достигает нуля.

Производительность

[ редактировать ]

Единственные дополнительные требования к памяти — это вспомогательный вектор L для хранения границ сегмента и постоянное количество других используемых переменных. Кроме того, каждый элемент перемещается (через временный буфер, то есть две операции перемещения) только один раз. Однако такая эффективность использования памяти имеет тот недостаток, что доступ к массиву осуществляется случайным образом, поэтому невозможно использовать преимущества кэша данных, меньшего, чем весь массив.

Как и во всех видах корзин, производительность критически зависит от баланса корзин. В идеальном случае сбалансированного набора данных каждый сегмент будет примерно одинакового размера. Если количество m сегментов линейно зависит от входного размера n , каждый сегмент имеет постоянный размер, поэтому сортировка одного сегмента с помощью O ( n 2 ) алгоритм, такой как сортировка вставками, имеет сложность O (1 2 ) = О (1) . Таким образом, время выполнения окончательной сортировки вставкой составляет m ⋅ ​​O(1) = O ( m ) = O ( n ) .

Выбор значения m , количества сегментов учитывает время, затрачиваемое на классификацию элементов (высокое m ), и время, затрачиваемое на последний шаг сортировки вставкой (низкое m ). Например, если m выбрано пропорционально n , то время выполнения окончательной сортировки вставкой составит m ⋅ ​​O( n 2 ) = О ( п 3/2 ) .

В худшем случае, когда почти все элементы находятся в нескольких сегментах, сложность алгоритма ограничивается производительностью окончательного метода сортировки сегментов, поэтому снижается до O ( n 2 ) . Варианты алгоритма улучшают производительность в худшем случае за счет использования более эффективных сортировок, таких как быстрая сортировка или рекурсивная флэш-сортировка, для сегментов, размер которых превышает определенный предел. [2] [3]

Для m = 0,1 n с равномерно распределенными случайными данными флеш-сортировка выполняется быстрее, чем пирамидальная сортировка для всех n , и быстрее, чем быстрая сортировка для n > 80 . он становится примерно в два раза быстрее, чем быстрая сортировка При n = 10000 . [1] Обратите внимание, что эти измерения были проведены в конце 1990-х годов, когда иерархии памяти гораздо меньше зависели от кэширования.

Из-за перестановок in situ , которые flashsort выполняет в процессе классификации, flashsort не является стабильным . Если требуется стабильность, можно использовать второй массив, чтобы элементы можно было классифицировать последовательно. Однако в этом случае алгоритму потребуется O ( n ) дополнительной памяти.

См. также

[ редактировать ]
  1. ^ Jump up to: Перейти обратно: а б с д Нойберт, Карл-Дитрих (февраль 1998 г.). «Алгоритм Flashsort1» . Журнал доктора Добба . 23 (2): 123–125, 131 . Проверено 6 ноября 2007 г.
  2. ^ Jump up to: Перейти обратно: а б Нойберт, Карл-Дитрих (1998). «Алгоритм FlashSort» . Проверено 6 ноября 2007 г.
  3. ^ Сяо, Ли; Чжан, Сяодун; Кубрихт, Стефан А. (2000). «Улучшение производительности памяти алгоритмов сортировки: эффективная для кэша быстрая сортировка» . Журнал экспериментальной алгоритмики ACM . 5 . CiteSeerX   10.1.1.43.736 . дои : 10.1145/351827.384245 . Архивировано из оригинала 2 ноября 2007 г. Проверено 6 ноября 2007 г.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: f71902e1a68984f9580f399e20ee909c__1713177000
URL1:https://arc.ask3.ru/arc/aa/f7/9c/f71902e1a68984f9580f399e20ee909c.html
Заголовок, (Title) документа по адресу, URL1:
Flashsort - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)