Сортировка ведром
Сорт | Алгоритм сортировки |
---|---|
Структура данных | Множество |
Худшая производительность | |
Средняя производительность | , где k — количество сегментов. . |
Наихудшая пространственная сложность |
Сортировка сегментами или сортировка ячеек — это алгоритм сортировки , который работает путем распределения элементов массива по нескольким сегментам. Затем каждая корзина сортируется индивидуально, либо с использованием другого алгоритма сортировки, либо путем рекурсивного применения алгоритма сортировки корзин. Это сортировка по распределению , обобщение сортировки по ячейкам , которая позволяет использовать несколько ключей в сегменте и является двоюродным братом поразрядной сортировки в варианте от наиболее значимого к наименее значимому разряду. Сортировка сегментами может быть реализована с помощью сравнений и, следовательно, также может рассматриваться как алгоритм сортировки сравнением . Вычислительная сложность зависит от алгоритма, используемого для сортировки каждого сегмента, количества используемых сегментов и равномерности распределения входных данных.
Сортировка сегментами работает следующим образом:
- Настройте массив изначально пустых «ведёр».
- Scatter : просмотр исходного массива, помещая каждый объект в свою корзину.
- Отсортируйте каждое непустое ведро.
- Сбор : посетите сегменты по порядку и поместите все элементы обратно в исходный массив.
Псевдокод [ править ]
function bucketSort(array, k) is buckets ← new array of k empty lists M ← 1 + the maximum key value in the array for i = 0 to length(array) do insert array[i] into buckets[floor(k × array[i] / M)] for i = 0 to k do nextSort(buckets[i]) return the concatenation of buckets[0], ...., buckets[k]
Пусть массив обозначает массив, который нужно отсортировать, а k обозначает количество используемых сегментов. Максимальное значение ключа можно вычислить за линейное время , однократно перебрав все ключи. Функция Floor должна использоваться для преобразования плавающего числа в целое число (и, возможно, также для приведения типов данных). Функция nextSort — это функция сортировки, используемая для сортировки каждого сегмента. Обычно используется сортировка вставками , но можно использовать и другие алгоритмы, например сортировку выбором или сортировку слиянием . Использование BucketSort в качестве nextSort создает родственник поразрядной сортировки ; в частности, случай n = 2 соответствует быстрой сортировке (хотя потенциально с плохим выбором опорной точки).
Анализ [ править ]
Анализ наихудшего случая [ править ]
Когда входные данные содержат несколько ключей, расположенных близко друг к другу (кластеризация), эти элементы, скорее всего, будут помещены в один и тот же сегмент, в результате чего некоторые сегменты будут содержать больше элементов, чем в среднем. Наихудший сценарий возникает, когда все элементы помещаются в одно ведро. Тогда общая производительность будет зависеть от алгоритма, используемого для сортировки каждого сегмента, например сортировка вставкой или алгоритмы сортировки сравнением , такие как сортировка слиянием .
Анализ среднего случая [ править ]
Рассмотрим случай, когда входные данные распределены равномерно. Первый шаг — инициализация сегментов и поиск максимального значения ключа в массиве — можно выполнить в время. Если деление и умножение можно производить за постоянное время, то раскидывание каждого элемента по своему ведру тоже стоит . Предположим, что для сортировки каждого сегмента используется сортировка вставками, тогда затраты на третий шаг , где длина сегмента индексируется . Поскольку речь идет о среднем времени, ожидание вместо этого необходимо оценить. Позволять быть случайной величиной, которая если элемент помещается в ведро , и в противном случае. У нас есть . Поэтому,
Последняя строка разделяет суммирование на случай и дело . Поскольку вероятность того, что объект будет распределен по ведру является , равно 1 с вероятностью и 0 в противном случае.
При суммировании получится
Наконец, сложность будет .
Последний шаг сортировки сегментов, который объединяет все отсортированные объекты в каждом сегменте, требует время. Таким образом, общая сложность равна . Обратите внимание, что если k выбрано равным , затем запускается сегментная сортировка среднее время при равномерном распределении входных данных. [1]
Оптимизации [ править ]
поместить неотсортированные элементы сегментов обратно в исходный массив Обычная оптимизация заключается в том, чтобы сначала , а затем запустить сортировку вставкой по всему массиву; поскольку время выполнения сортировки вставкой зависит от того, насколько далеко каждый элемент находится от своей конечной позиции, количество сравнений остается относительно небольшим, а иерархию памяти лучше использовать, храня список в памяти непрерывно. [2]
Если входное распределение известно или может быть оценено, часто можно выбрать сегменты с постоянной плотностью (а не просто с постоянным размером). Это позволяет средняя временная сложность даже без равномерно распределенных входных данных.
Варианты [ править ]
Общая сортировка сегментов [ править ]
Самый распространенный вариант сортировки сегментов работает со списком из n числовых входных данных между нулем и некоторым максимальным значением M и делит диапазон значений на n сегментов, каждый размером M / n . Если каждый сегмент сортируется с использованием сортировки вставками , можно показать, что сортировка выполняется за ожидаемое линейное время (где берется среднее значение по всем возможным входным данным). [3] Однако производительность такого рода снижается при кластеризации; если много значений встречаются близко друг к другу, все они попадут в одну корзину и будут медленно сортироваться. Этого снижения производительности можно избежать в исходном алгоритме сортировки сегментов, предполагая, что входные данные генерируются случайным процессом, который равномерно распределяет элементы по интервалу [0,1) . [1]
ПроксмапСорт [ править ]
Подобно общей сортировке сегментов, описанной выше, ProxmapSort работает путем разделения массива ключей на подмассивы с помощью функции «ключ карты», которая сохраняет частичный порядок ключей; поскольку каждый ключ добавляется в свой подмассив, для сохранения сортировки этого подмассива используется сортировка вставкой, в результате чего после завершения ProxmapSort весь массив оказывается в отсортированном порядке. ProxmapSort отличается от сегментной сортировки тем, что использует ключ карты для размещения данных примерно там, где они находятся, в отсортированном порядке, создавая «проксмап» — сопоставление близости — ключей.
Сортировка гистограммы [ править ]
Другой вариант сортировки по сегментам, известный как сортировка по гистограмме или сортировка по подсчету, добавляет начальный проход, который подсчитывает количество элементов, попадающих в каждый сегмент, с помощью массива счетчиков. [4] Используя эту информацию, значения массива можно упорядочить в последовательность сегментов на месте посредством последовательности обменов, не оставляя места для хранения сегментов. [ не удалось пройти проверку ]
сортировка почтальона [ править ]
— Сортировка почтальона это вариант сортировки сегментами, в котором используется иерархическая структура элементов, обычно описываемая набором атрибутов. Это алгоритм, используемый машинами для сортировки писем в почтовых отделениях : почта сначала сортируется между внутренней и международной; затем по штату, провинции или территории; затем почтовым отделением назначения; затем по маршрутам и т. д. Поскольку ключи не сравниваются друг с другом, время сортировки равно O( cn ), где c зависит от размера ключа и количества сегментов. Это похоже на поразрядную сортировку , которая работает «сверху вниз» или «сначала наиболее значащая цифра». [5]
Сортировка в случайном порядке [ править ]
Сортировка в случайном порядке [6] — это вариант групповой сортировки, который начинается с удаления первой 1/8 из n элементов, подлежащих сортировке, рекурсивно сортирует их и помещает в массив. При этом создается n /8 «корзин», по которым распределяются оставшиеся 7/8 предметов. Затем каждое «ведро» сортируется, и «корзины» объединяются в отсортированный массив.
Сравнение с другими алгоритмами сортировки [ править ]
Сортировку сегментами можно рассматривать как обобщение сортировки по счету ; Фактически, если размер каждого сегмента равен 1, то сортировка сегментов вырождается в сортировку с подсчетом. Переменный размер сегмента сортировки сегментов позволяет использовать память O( n ) вместо памяти O( M ), где M — количество различных значений; взамен он отказывается от подсчета сортировки O( n + M худшего поведения ).
Сортировка сегментами с двумя сегментами по сути является версией быстрой сортировки , в которой опорное значение всегда выбирается как среднее значение диапазона значений. Хотя этот выбор эффективен для равномерно распределенных входных данных, другие способы выбора опорных точек при быстрой сортировке, такие как случайно выбранные опорные точки, делают ее более устойчивой к кластеризации в распределении входных данных.
алгоритм n -сторонний сортировки слиянием также начинается с распределения списка на n подсписков и сортировки каждого из них; однако подсписки, созданные сортировкой слиянием, имеют перекрывающиеся диапазоны значений, поэтому их нельзя повторно объединить путем простой конкатенации, как при сортировке сегментов. Вместо этого они должны чередоваться с помощью алгоритма слияния. Однако эти дополнительные расходы уравновешиваются более простой фазой разброса и возможностью гарантировать, что каждый подсписок имеет одинаковый размер, обеспечивая хорошую временную привязку для наихудшего случая.
сверху вниз Поразрядную сортировку можно рассматривать как особый случай сортировки по сегментам, где диапазон значений и количество сегментов ограничены степенью двойки. Следовательно, размер каждого сегмента также равен степени двойки, и процедуру можно применять рекурсивно. Этот подход может ускорить фазу разброса, поскольку нам нужно только проверить префикс битового представления каждого элемента, чтобы определить его сегмент.
Ссылки [ править ]
- ^ Jump up to: Перейти обратно: а б Томас Х. Кормен ; Чарльз Э. Лейзерсон ; Рональд Л. Ривест и Клиффорд Стейн . Введение в алгоритмы .
Сортировка сегментами выполняется в среднем за линейное время. Как и сортировка по подсчету, сортировка по сегментам выполняется быстро, поскольку она предполагает что-то относительно входных данных. В то время как сортировка подсчетом предполагает, что входные данные состоят из целых чисел в небольшом диапазоне, сортировка сегментами предполагает, что входные данные генерируются случайным процессом, который равномерно распределяет элементы в интервале [0,1) . Идея сортировки сегментов состоит в том, чтобы разделить интервал [0, 1) на n подинтервалов или сегментов одинакового размера, а затем распределить n входных чисел по сегментам. Поскольку входные данные равномерно распределены по [0, 1) , мы не ожидаем, что в каждое ведро попадет много чисел. Чтобы получить выходные данные, мы просто сортируем числа в каждом сегменте, а затем просматриваем сегменты по порядку, перечисляя элементы в каждом.
- ^ Корвин, Э. и Логар, А. «Сортировка за линейное время - вариации сортировки по кольцу». Журнал компьютерных наук в колледжах , 20, 1, стр. 197–202. Октябрь 2004 года.
- ^ Томас Х. Кормен , Чарльз Э. Лейзерсон , Рональд Л. Ривест и Клиффорд Штайн . Введение в алгоритмы , второе издание. MIT Press и McGraw-Hill, 2001. ISBN 0-262-03293-7 . Раздел 8.4: Сортировка по сегментам, стр. 174–177.
- ^ Словарь алгоритмов и структур данных NIST: сортировка гистограммы
- ^ «Разработка программного обеспечения Роберта Рэми» .
- ↑ Революционно новый сорт от Джона Коэна, 26 ноября 1997 г.
- Пол Э. Блэк «Сортировка почтальона» из Словаря алгоритмов и структур NIST данных .
- Роберт Рэми , «Сортировка почтальона» , журнал C Users Journal, август 1992 г.
- Словарь алгоритмов и структур данных NIST: сортировка по корзинам