Radix sort - Radix sort - Wikipedia

Radix sort
Учебный классАлгоритм сортировки
Структура данныхМножество
Худший случай спектакль, где w - количество битов, необходимых для хранения каждого ключа.
Худший случай космическая сложность

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

Сортировка Radix может применяться к данным, которые можно сортировать лексикографически, будь то целые числа, слова, перфокарты, игральные карты или Почта.

История

Сортировка Radix восходит к 1887 году работами Герман Холлерит на счетные машины.[1] Алгоритмы сортировки Radix получили широкое распространение как способ сортировки перфокарты еще в 1923 г.[2]

Первый вычислительный алгоритм с эффективным использованием памяти был разработан в 1954 г. Массачусетский технологический институт к Гарольд Х. Сьюард. Компьютеризированная радиальная сортировка ранее отвергалась как непрактичная из-за предполагаемой потребности в переменном распределении сегментов неизвестного размера. Нововведение Сьюарда заключалось в использовании линейного сканирования для предварительного определения требуемых размеров сегментов и смещений, что позволяло единственное статическое распределение вспомогательной памяти. Линейное сканирование тесно связано с другим алгоритмом Сьюарда - счетная сортировка.

В современную эпоху поразрядные сортировки чаще всего применяются к коллекциям двоичных файлов. струны и целые числа. В некоторых тестах было показано, что он работает быстрее, чем другие алгоритмы сортировки общего назначения, иногда от 50% до трех раз быстрее.[3][4][5]

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

Порядок цифр

Сортировка Radix может быть реализована, чтобы начать с любого самая значимая цифра (MSD) или младшая цифра (ЛСД). Например, с 1234, можно было начать с 1 (MSD) или 4 (LSD).

LSD-сортировка по основанию счисления обычно использует следующий порядок сортировки: короткие ключи предшествуют более длинным, а затем сортируются ключи той же длины. лексикографически. Это совпадает с нормальным порядком целочисленных представлений, как последовательность [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]. Типы ЛСД обычно стабильные сорта.

Сортировка по основанию MSD лучше всего подходит для сортировки строк или целочисленных представлений фиксированной длины. Последовательность вроде [b, c, e, d, f, g, ba] будет отсортировано как [b, ba, c, d, e, f, g]. Если для сортировки целых чисел переменной длины по основанию 10 используется лексикографический порядок, то числа от 1 до 10 будут выводиться как [1, 10, 2, 3, 4, 5, 6, 7, 8, 9], как если бы более короткие клавиши были выровнены по левому краю и дополнены справа пустыми символами, чтобы сделать более короткие клавиши такими же длинными, как и самая длинная. Сортировка MSD не обязательно стабильна, если всегда необходимо сохранять исходный порядок повторяющихся ключей.

Помимо порядка обхода, сортировки MSD и LSD отличаются обработкой входных данных переменной длины. LSD-сортировки могут группироваться по длине, сортировать каждую группу по основанию, а затем объединять группы в порядке размера. Сортировка MSD должна эффективно «расширять» все более короткие ключи до размера самого большого ключа и соответственно сортировать их, что может быть более сложным, чем группировка, требуемая LSD.

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

Примеры

Наименьшая значащая цифра

Список ввода (основание 10):

[170, 45, 75, 90, 2, 802, 2, 66]

Начиная с самой правой (последней) цифры, отсортируйте числа на основе этой цифры:

[{170, 90}, {02, 802, 02}, {45, 75}, {66}]
Обратите внимание, что 0 добавляется перед двумя двойками, так что 802 сохраняет свой относительный порядок, как в предыдущем списке (то есть помещается перед вторыми 2), на основе достоинства второй цифры.

Сортировка по следующей левой цифре:

[{02, 802, 02}, {45}, {66}, {170, 75}, {90}]

И, наконец, по крайней левой цифре:

[{002, 002, 045, 066, 075, 090}, {170}, {802}]

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

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

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

Старшая цифра, прямая рекурсивная

Список ввода, числовые строки фиксированной ширины с ведущими нулями:

[170, 045, 075, 025, 002, 024, 802, 066]

Первая цифра, в скобках указаны ведра:

[{045, 075, 025, 002, 024, 066}, {170}, {802}]
Обратите внимание, что 170 и 802 уже завершены, потому что они все, что остались в своих корзинах, поэтому дальнейшая рекурсия не требуется.

Следующая цифра:

[{ {002}, {025, 024}, {045}, {066}, {075} }, 170, 802]

Последняя цифра:

[ 002, { {024}, {025} }, 045, 066, 075 , 170, 802]

Остается только конкатенация:

[002, 024, 025, 045, 066, 075, 170, 802]

Сложность и производительность

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

Оптимизированная сортировка по системе счисления может быть очень быстрой при работе в подходящей для них области.[6]Они ограничены лексикографическими данными, но для многих практических приложений это не ограничение. Большие размеры ключей могут препятствовать реализации LSD, когда вызванное количество проходов становится узким местом.[2]

Специализированные варианты

Реализации поразрядной сортировки MSD на месте

Двоичная сортировка по основанию MSD, также называемая двоичной быстрой сортировкой, может быть реализована на месте путем разделения входного массива на две ячейки - ячейку 0 и ячейку 1. Бин 0s увеличивается с начала массива, тогда как интервал 1s увеличивается с конца массива. Граница бина 0s помещается перед первым элементом массива. Граница ячейки размером 1 с помещается после последнего элемента массива. Проверяется старший бит первого элемента массива. Если этот бит равен 1, то первый элемент заменяется элементом перед границей ячейки 1s (последний элемент массива), а ячейка 1s увеличивается на один элемент за счет уменьшения индекса массива границы 1s. Если этот бит равен 0, то первый элемент остается в своем текущем местоположении, а интервал 0s увеличивается на один элемент. Следующим исследуемым элементом массива является тот, который находится перед границей бина 0 с (т. Е. Первый элемент, который не находится в ячейке 0 или ячейке 1). Этот процесс продолжается до тех пор, пока ячейки нулей и единиц не достигнут друг друга. Бункер 0s и интервал 1s затем рекурсивно сортируются на основе следующего бита каждого элемента массива. Рекурсивная обработка продолжается до тех пор, пока для сортировки не будет использован младший бит.[7][8] Обработка целых чисел со знаком требует обработки самого старшего бита в противоположном смысле, а затем беззнаковой обработки остальных битов.

Сортировку двоичной системы счисления MSD на месте можно расширить до более крупной системы счисления и сохранить возможности на месте. Счетная сортировка используется для определения размера каждой ячейки и их начального индекса. Перестановка используется для помещения текущего элемента в его корзину с последующим расширением границы корзины. Когда элементы массива сканируются, ячейки пропускаются, и обрабатываются только элементы между ячейками, пока не будет обработан весь массив и все элементы не окажутся в своих соответствующих ячейках. Количество ячеек такое же, как и используемая система счисления, например 16 ячеек для системы счисления 16. Каждый проход основан на одной цифре (например, 4 бита на цифру в случае 16-кратной системы счисления), начиная с самая значимая цифра. Затем каждая ячейка рекурсивно обрабатывается с использованием следующей цифры, пока все цифры не будут использованы для сортировки.[9][10]

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

Стабильные реализации поразрядной сортировки MSD

Сортировка по основанию MSD может быть реализована как стабильный алгоритм, но требует использования буфера памяти того же размера, что и входной массив. Эта дополнительная память позволяет сканировать входной буфер от первого элемента массива до последнего и перемещать элементы массива в целевые ячейки в том же порядке. Таким образом, одинаковые элементы будут помещены в буфер памяти в том же порядке, в котором они были во входном массиве. Алгоритм на основе MSD использует дополнительный буфер памяти в качестве вывода на первом уровне рекурсии, но меняет местами ввод и вывод на следующем уровне рекурсии, чтобы избежать накладных расходов на копирование результата вывода обратно во входной буфер. Каждый из бинов рекурсивно обрабатывается, как это делается для сортировки по основанию MSD на месте. После завершения сортировки по последней цифре выходной буфер проверяется, чтобы увидеть, является ли он исходным входным массивом, и если это не так, выполняется единичная копия. Если размер цифр выбран так, что размер ключа, деленный на размер цифры, является четным числом, копии в конце избегают.[11]

Гибридные подходы

Радиксная сортировка, например двухпроходный метод, где счетная сортировка используется во время первого прохода каждого уровня рекурсии, имеет большие постоянные накладные расходы. Таким образом, когда ячейки становятся маленькими, следует использовать другие алгоритмы сортировки, например вставка сортировки. Хорошая реализация вставка сортировки работает быстро для небольших массивов, стабильно, на месте и может значительно ускорить сортировку по основанию.

Приложение к параллельным вычислениям

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

На верхнем уровне рекурсии возможность параллелизма находится в счетная сортировка часть алгоритма. Подсчет является высокопараллельным, подчиняется шаблону parallel_reduce и хорошо распределяет работу между несколькими ядрами до достижения предела пропускной способности памяти. Эта часть алгоритма имеет независимый от данных параллелизм. Однако обработка каждого бина на последующих уровнях рекурсии зависит от данных. Например, если бы все ключи имели одно и то же значение, тогда была бы только одна ячейка с любыми элементами в ней, и параллелизм был бы недоступен. Для случайных входных данных все бины будут заполнены почти одинаково, и будет доступно большое количество возможностей параллелизма.[12]

Обратите внимание, что существуют более быстрые алгоритмы параллельной сортировки, например оптимальная сложность O (log (п)) принадлежат трём венграм и Ричарду Коулу.[13][14] и Дозатор с битонная сортировка слиянием имеет алгоритмическую сложность O (log2(п)), все из которых имеют более низкую алгоритмическую временную сложность для поразрядной сортировки на CREW-PRAM. Самые быстрые известные сортировки PRAM были описаны в 1991 году Дэвидом Пауэрсом с помощью параллельной быстрой сортировки, которая может работать за время O (log (n)) на CRCW-PRAM с п процессоров, выполняя неявное разбиение, а также основную сортировку, которая работает с тем же трюком в O (k), куда k максимальная длина ключа.[15] Однако ни архитектура PRAM, ни отдельный последовательный процессор на самом деле не могут быть построены таким образом, чтобы масштабироваться без количества постоянных разветвление задержки ворот за цикл увеличиваются как O (log (п)), так что по сути конвейерная версия bitonic mergesort Batcher и O (log (п)) Все сортировки PRAM - O (log2(п)) с точки зрения тактовых циклов, причем Пауэрс признает, что константа Батчера будет иметь более низкую константу с точки зрения задержек ворот, чем его параллельный быстрая сортировка и сортировка по основанию или по Коулу Сортировка слиянием, для независимого от длины ключа сортировочная сеть из O (nlog2(п)).[16]

Сортировка по основанию Trie

Радикс-сортировку также можно выполнить, построив три (или же радиксное дерево) из входного набора и выполняя Предварительный заказ обход. Это похоже на отношения между heapsort и куча структура данных. Это может быть полезно для определенных типов данных, см. взрывной.

Смотрите также

Рекомендации

  1. ^ США 395781  и Великобритания 327 
  2. ^ а б Дональд Кнут. Искусство программирования, Том 3: Сортировка и поиск, Третье издание. Аддисон-Уэсли, 1997. ISBN  0-201-89685-0. Раздел 5.2.5: Сортировка по распределению, стр. 168–179.
  3. ^ «Я написал более быстрый алгоритм сортировки». 28 декабря 2016.
  4. ^ "Сортировка по основанию быстрее, чем быстрая сортировка для целочисленных массивов?". erik.gorset.no.
  5. ^ "Шаблон функции integer_sort - 1.62.0". www.boost.org.
  6. ^ «Эффективная сортировка больших наборов строк на основе Trie».
  7. ^ Р. Седжвик, "Алгоритмы в C ++", третье издание, 1998 г., стр. 424-427
  8. ^ Дуваненко, Виктор Я. «Улучшение алгоритмов посредством измерения производительности: Часть 2». Доктора Добба.
  9. ^ Дуваненко, Виктор Я. «Улучшение алгоритмов посредством измерения производительности: Часть 3». Доктора Добба.
  10. ^ Дуваненко, Виктор Я. "Упрощенная параллельная сортировка по месту". Доктора Добба.
  11. ^ Дуваненко, Виктор Я. «Улучшение алгоритмов посредством измерения производительности: Часть 4». Доктора Добба.
  12. ^ Дуваненко, Виктор Я. «Параллельная сортировка на месте с N-битным основанием». Доктора Добба.
  13. ^ А. Гиббонс и В. Риттер, Эффективные параллельные алгоритмы. Издательство Кембриджского университета, 1988.
  14. ^ Х. Казанова и др., Параллельные алгоритмы. Чепмен и Холл, 2008.
  15. ^ Дэвид М. В. Пауэрс, Параллельная быстрая и радиксная сортировка с оптимальным ускорением, Труды Международной конференции по параллельным вычислительным технологиям.. Новосибирск. 1991.
  16. ^ Дэвид М. В. Пауэрс, Параллельное объединение: практическая сложность, Австралийский семинар по компьютерной архитектуре, Университет Флиндерса, январь 1995 г.

внешняя ссылка