Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску
Шаги Shellsort.
Замена пар элементов на последовательных шагах Shellsort с пробелами 5, 3, 1

Shellsort , также известный как сортировка Shell или метод Shell , является сортировкой на месте сравнения . Это можно рассматривать как обобщение сортировки путем обмена ( пузырьковая сортировка ) или сортировки путем вставки ( сортировка вставкой ). [3] Метод начинается с сортировки пар элементов на большом расстоянии друг от друга, а затем постепенного уменьшения разрыва между сравниваемыми элементами. Начав с удаленных друг от друга элементов, он может переместить некоторые неуместные элементы на место быстрее, чем простой обмен ближайшими соседями. Дональд Шелл опубликовал первую подобную версию в 1959 году. [4] [5]Время работы Shellsort сильно зависит от используемой им последовательности пропусков. Для многих практических вариантов определение их временной сложности остается открытой проблемой .

Описание [ править ]

Shellsort - это оптимизация сортировки вставкой, которая позволяет обмениваться элементами, которые находятся далеко друг от друга. Идея состоит в том, чтобы организовать список элементов таким образом, чтобы начиная с любого h- го элемента получался отсортированный список. Такой список называется h- отсортированным. Его также можно представить как h чередующихся списков, каждый из которых отсортирован по отдельности. [6] Начало с большими значениями h позволяет элементам перемещаться на большие расстояния в исходном списке, быстро уменьшая большое количество беспорядка и оставляя меньше работы для выполнения меньших шагов h- сортировки. [7] Если список затем k-отсортирован для некоторого меньшего целого числа k, то список остается h- отсортированным. Следуя этой идее для убывающей последовательности значений h, оканчивающихся на 1, гарантированно в конечном итоге останется отсортированный список. [6]

Проще говоря, это означает, что если у нас есть массив из 1024 чисел, наш первый пробел ( h ) может быть 512. Затем мы просматриваем список, сравнивая каждый элемент в первой половине с элементом во второй половине. Наш второй пробел ( k ) равен 256, что разбивает массив на четыре раздела (начиная с 0,256,512,768), и мы убеждаемся, что первые элементы в каждом разделе отсортированы относительно друг друга, затем второй элемент в каждом разделе и т. Д. . На практике последовательность пропусков может быть любой, но последний пробел всегда равен 1 для завершения сортировки (фактически завершение обычной сортировки вставкой).

Пример выполнения Shellsort с пробелами 5, 3 и 1 показан ниже.

Первый проход, 5-сортировка, выполняет сортировку вставкой на пяти отдельных подмассивах ( a 1 , a 6 , a 11 ), ( a 2 , a 7 , a 12 ), ( a 3 , a 8 ), ( a 4 , a 9 ), ( а 5 , а 10 ). Например, он изменяет подмассив ( a 1 , a 6 , a 11) с (62, 17, 25) на (17, 25, 62). Следующий проход, 3-сортировка, выполняет сортировку вставкой на трех подмассивах ( a 1 , a 4 , a 7 , a 10 ), ( a 2 , a 5 , a 8 , a 11 ), ( a 3 , a 6 , а 9 , а 12 ). Последний проход, 1-сортировка, представляет собой обычную сортировку вставкой всего массива ( a 1 , ..., a 12 ).

Как показывает пример, подмассивы, с которыми работает Shellsort, изначально короткие; позже они стали длиннее, но почти заказаны. В обоих случаях сортировка вставкой работает эффективно.

Shellsort нестабилен : он может изменить относительный порядок элементов с одинаковыми значениями. Это адаптивный алгоритм сортировки, поскольку он выполняется быстрее, когда входные данные частично отсортированы.

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

Использование последовательности пробелов Марцина Чиуры с сортировкой по внутренней вставке.

# Сортировать массив a [0 ... n-1]. пробелы  =  [ 701 ,  301 ,  132 ,  57 ,  23 ,  10 ,  4 ,  1 ]# Начните с самого большого пробела и уменьшите пробел до 1 foreach  ( пробел  в  пробелах ) {  # Выполните сортировку вставки пробелов для этого размера пробела.  # Первые элементы промежутка a [0..gap-1] уже находятся в порядке с промежутками  # продолжайте добавлять еще один элемент, пока весь массив не будет отсортирован  по  промежуткам ( i  =  gap ;  i  <  n ;  i  + =  1 )  {  # add a [i] к элементам, которые были отсортированы по пробелам  # сохраните a [i] в ​​temp и сделайте отверстие в позиции i  temp  =  a [ i ] # сдвигаем ранее отсортированные по пробелам элементы до тех пор, пока не будет найдено правильное место для a [i]  для  ( j  =  i ;  j  > =  gap  and  a [ j  -  gap ]  >  temp ;  j  - =  gap )  {  a [ j ]  =  a [ j  -  gap ]  }  # поместите temp (исходный a [i]) в правильное место  a [ j ]  =  temp  } }

Последовательности пробелов [ править ]

Вопрос о том, какую последовательность пробелов использовать, является трудным. Каждая последовательность пробелов, содержащая 1, дает правильную сортировку (так как это делает последний проход обычной сортировкой вставкой); однако свойства полученных таким образом версий Shellsort могут сильно отличаться. Слишком мало пропусков замедляет проходы, а слишком большое количество пропусков приводит к накладным расходам.

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

Когда двоичное представление N содержит много последовательных нулей, Shellsort с использованием исходной последовательности пробелов Shell выполняет Θ ( N 2 ) сравнений в худшем случае. Например, этот случай имеет место для N, равного степени двойки, когда элементы больше и меньше медианы занимают нечетные и четные позиции соответственно, поскольку они сравниваются только на последнем проходе.

Хотя он имеет более высокую сложность, чем O ( N  log  N ), который является оптимальным для сортировок сравнения, версия Pratt поддается сортировке сетей и имеет ту же асимптотическую сложность ворот, что и битонный сортировщик Batcher .

Гоннет и Баеза-Йейтс заметили, что Shellsort в среднем делает наименьшее количество сравнений, когда отношение последовательных пропусков примерно равно 2,2. [13] Вот почему их последовательность с коэффициентом 2.2 и последовательность Токуды с коэффициентом 2.25 оказываются эффективными. Однако неизвестно, почему это так. Седжвик рекомендует использовать гэпы, которые имеют низкие наибольшие общие делители или попарно взаимно просты . [16] [ неудачная проверка ]

Что касается среднего числа сравнений, последовательность Чиуры [15] имеет наилучшую известную производительность; пропуски из 701 не были определены, но последовательность может быть расширена в соответствии с рекурсивной формулой .

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

Если максимальный размер входных данных мал, что может произойти, если Shellsort используется на небольших подмассивах другим алгоритмом рекурсивной сортировки, таким как быстрая сортировка или сортировка слиянием , то можно составить таблицу оптимальной последовательности для каждого размера входных данных. [17]

Вычислительная сложность [ править ]

Имеет место следующее свойство: после h 2 -сортировки любого h 1 -сортированного массива массив остается h 1 -сортированным. [18] Каждый h 1 -сортированный и h 2 -сортированный массив также ( a 1 h 1 + a 2 h 2 ) -сортированный для любых неотрицательных целых чисел a 1 и a 2 . Таким образом, наихудшая сложность Shellsort связана с проблемой Фробениуса : для заданных целых чисел h 1 , ..., h nс НОД = 1, число Фробениуса г ( ч 1 , ..., ч п ) наибольшее целое число , которое не может быть представлено как в 1 ч 1 + ... + п ч п с целыми неотрицательными 1 , .. ., а н . Используя известные формулы для чисел Фробениуса, мы можем определить наихудшую сложность Shellsort для нескольких классов разрывных последовательностей. [19] Подтвержденные результаты показаны в таблице выше.

Что касается среднего количества операций, ни один из доказанных результатов не касается практической последовательности пропусков. Для пробелов, равных степени двойки, Эспелид вычислил это среднее как . [20] Кнут определил среднюю сложность сортировки N -элементного массива с двумя пробелами ( h , 1) . [3] Отсюда следует, что двухпроходная сортировка Shellsort с h = ( N 1/3 ) делает в среднем O ( N 5/3 ) сравнений / инверсий / время работы. Яо обнаружил среднюю сложность трехпроходной сортировки Shellsort. [21] Его результат был уточнен Янсоном. и Кнут: [22] среднее количество сравнений / инверсий / времени выполнения, сделанных во время сортировки Shell с тремя пробелами ( ch , cg , 1), где h и g взаимно просты, находится в первом проходе, во втором проходе и в третий проход. ψ ( h , g ) в последней формуле - сложная функция, асимптотически равная . В частности, когда h = Θ ( N 7/15 ) и g = Θ ( N 1/5 ), среднее время сортировки составляет O ( N 23/15).

На основе экспериментов, он высказал предположение , что ShellSort с Хиббард прогонами последовательности разрыва «ы в O ( N 5/4 ) Среднее времени, [3] и что последовательность Гоння и Баэс-Йетс требует в среднем 0,41 N  LN  N  (LN LN  N  + 1/6) элемент перемещается. [13] Приближение среднего числа операций, ранее выдвигавшихся для других последовательностей, не срабатывает, если отсортированные массивы содержат миллионы элементов.

На графике ниже показано среднее количество сравнений элементов в различных вариантах Shellsort, разделенное на теоретическую нижнюю границу, то есть log 2 N !, где последовательность 1, 4, 10, 23, 57, 132, 301, 701 была расширена. по формуле .

Применяя теорию сложности Колмогорова , Цзян, Ли и Витаньи доказали следующую нижнюю оценку для порядка среднего числа операций / времени выполнения в p- проходной сортировке Shellsort: Ω ( pN 1 + 1 / p ) при p  ≤ log 2 Н и Ω ( пН ) при р  > войти 2 N . [23] Таким образом, Shellsort имеет перспективы работать за среднее время, которое асимптотически растет как N log Nтолько при использовании последовательностей пробелов, количество пробелов которых растет пропорционально логарифму размера массива. Однако неизвестно, сможет ли Shellsort достичь этого асимптотического порядка средней сложности, который является оптимальным для сортировок сравнения. Нижняя оценка была улучшена Витаньи [24] для каждого числа проходов в точку . Из этого результата следует, например, нижняя оценка Цзян-Ли-Витаньи для всех-pass последовательности приращений и улучшает эту нижнюю границу для определенных последовательностей приращений. Фактически все границы (нижняя и верхняя), известные в настоящее время для среднего случая, точно совпадают с этой нижней границей. Например, это дает новый результат, состоящий в том, что верхняя граница Янсона-Кнута соответствует результирующей нижней границе для используемой последовательности приращений, показывая, что трехпроходная сортировка Shellsort для этой последовательности приращений использует сравнения / инверсии / время выполнения. Формула позволяет нам искать последовательности приращения, которые дают неизвестные нижние границы; например, последовательность приращения для четырех проходов, нижняя граница которой больше, чем для последовательности приращения . Нижняя граница становится

Наихудшая сложность любой версии Shellsort - более высокого порядка: Plaxton, Poonen и Suel показали, что она растет по крайней мере так же быстро, как . [25] [26]

Приложения [ править ]

Shellsort выполняет больше операций и имеет более высокий коэффициент промахов кеша, чем quicksort . Однако, поскольку он может быть реализован с использованием небольшого количества кода и не использует стек вызовов , некоторые реализации функции qsort в стандартной библиотеке C, ориентированной на встроенные системы, используют ее вместо быстрой сортировки. Shellsort, например, используется в библиотеке uClibc . [27] По тем же причинам в прошлом Shellsort использовался в ядре Linux . [28]

Shellsort также может служить под-алгоритмом интроспективной сортировки для сортировки коротких подмассивов и предотвращения замедления, когда глубина рекурсии превышает заданный предел. Этот принцип используется, например, в компрессоре bzip2 . [29]

См. Также [ править ]

  • Расческа сортировка

Ссылки [ править ]

  1. ^ a b c Пратт, Воан Рональд (1979). Shellsort and Sorting Networks (Выдающиеся диссертации по компьютерным наукам) . Гирлянда. ISBN 978-0-8240-4406-0.
  2. ^ "Shellsort & Сравнение" .
  3. ^ a b c d e Кнут, Дональд Э. (1997). «Метод Шелл». Искусство программирования. Том 3: Сортировка и поиск (2-е изд.). Ридинг, Массачусетс: Эддисон-Уэсли. С. 83–95. ISBN 978-0-201-89685-5.
  4. ^ а б Шелл, DL (1959). «Процедура высокоскоростной сортировки» (PDF) . Коммуникации ACM . 2 (7): 30–32. DOI : 10.1145 / 368370.368387 .
  5. ^ Некоторые старые учебники и справочные материалы называют это сортом «Шелл-Мецнер» в честь Марлен Мецнер Нортон , но, по словам Мецнер, «я не имел к этому никакого отношения, и мое имя никогда не должно было быть связано с ним». См. «Сортировка по скорлупе» . Национальный институт стандартов и технологий . Проверено 17 июля 2007 года .
  6. ^ a b c Седжвик, Роберт (1998). Алгоритмы в C . 1 (3-е изд.). Эддисон-Уэсли. С.  273–281 . ISBN  978-0-201-31452-6.
  7. ^ Керниган, Брайан В .; Ричи, Деннис М. (1996). Язык программирования C (2-е изд.). Прентис Холл. п. 62. ISBN  978-7-302-02412-5.
  8. ^ Франк, RM; Лазарь, РБ (1960). «Процедура высокоскоростной сортировки». Коммуникации ACM . 3 (1): 20–22. DOI : 10.1145 / 366947.366957 .
  9. ^ Хиббард, Томас Н. (1963). «Эмпирическое исследование минимальной сортировки памяти». Коммуникации ACM . 6 (5): 206–213. DOI : 10.1145 / 366552.366557 .
  10. ^ Папернов, АА; Стасевич, Г.В. (1965). «Метод сортировки информации в компьютерной памяти» (PDF) . Проблемы передачи информации . 1 (3): 63–75.
  11. ^ Incerpi, Джанет; Седжвик, Роберт (1985). «Улучшенные верхние границы для сортировки по шеллу» (PDF) . Журнал компьютерных и системных наук . 31 (2): 210–224. DOI : 10.1016 / 0022-0000 (85) 90042-х .
  12. ^ Седжвик, Роберт (1986). «Новая верхняя граница для Shellsort». Журнал алгоритмов . 7 (2): 159–173. DOI : 10.1016 / 0196-6774 (86) 90001-5 .
  13. ^ a b c Gonnet, Gaston H .; Баеза-Йейтс, Рикардо (1991). «Шеллсорт». Справочник по алгоритмам и структурам данных: на языке Pascal и C (2-е изд.). Ридинг, Массачусетс: Эддисон-Уэсли. С. 161–163. ISBN 978-0-201-41607-7. Обширные эксперименты показывают, что последовательность, определенная как α = 0,45454 <5/11, работает значительно лучше, чем другие последовательности. Самый простой способ вычислить ⌊0.45454 п является использованием целочисленной арифметики.(5 * n — 1)/11
  14. ^ Tokuda, Наойуки (1992). «Улучшенная сортировка по шеллам». В ван Левен, Ян (ред.). Материалы 12-го Всемирного компьютерного конгресса ИФИП по алгоритмам, программному обеспечению, архитектуре . Амстердам: Издательство Северной Голландии, стр. 449–457. ISBN 978-0-444-89747-3.
  15. ^ a b Ciura, Marcin (2001). «Лучшие приращения для среднего случая сортировки шелл» (PDF) . В Freiwalds, Rusins ​​(ред.). Материалы 13-го Международного симпозиума по основам теории вычислений . Лондон: Springer-Verlag. С. 106–117. ISBN  978-3-540-42487-1.
  16. ^ Седжвик, Роберт (1998). «Шеллсорт». Алгоритмы в C ++, части 1–4: основы, структура данных, сортировка, поиск . Ридинг, Массачусетс: Эддисон-Уэсли. С. 285–292. ISBN 978-0-201-35088-3.
  17. ^ Forshell, Олоф (22 мая 2018). "Как выбрать длину моих подпоследовательностей для сортировки по оболочке?" . Переполнение стека . Дополнительный комментарий к самой быстрой последовательности пробелов для сортировки оболочки? (23 мая 2018 г.).
  18. Гейл, Дэвид ; Карп, Ричард М. (апрель 1972 г.). «Феномен в теории сортировки» (PDF) . Журнал компьютерных и системных наук . 6 (2): 103–115. DOI : 10.1016 / S0022-0000 (72) 80016-3 .
  19. ^ Selmer, Эрнст С. (март 1989). "О Shellsort и проблеме Фробениуса" (PDF) . BIT Численная математика . 29 (1): 37–40. DOI : 10.1007 / BF01932703 . hdl : 1956/19572 .
  20. ^ Espelid Терье О. (декабрь 1973). «Анализ алгоритма сортировки шелл». BIT Численная математика . 13 (4): 394–400. DOI : 10.1007 / BF01933401 . Цитируемый результат представляет собой уравнение (8) на стр. 399.
  21. Яо, Эндрю Чи-Чи (1980). "Анализ ( h , k , 1) -Shellsort" (PDF) . Журнал алгоритмов . 1 (1): 14–50. DOI : 10.1016 / 0196-6774 (80) 90003-6 . STAN-CS-79-726.
  22. ^ Янсон, Сванте ; Кнут, Дональд Э. (1997). «Shellsort с тремя приращениями» (PDF) . Случайные структуры и алгоритмы . 10 (1–2): 125–142. arXiv : cs / 9608105 . CiteSeerX 10.1.1.54.9911 . DOI : 10.1002 / (SICI) 1098-2418 (199701/03) 10: 1/2 <125 :: AID-RSA6> 3.0.CO; 2-X .  
  23. ^ Цзян, Тао; Ли, Мин ; Витани, Пол (сентябрь 2000 г.). "Нижняя граница средней сложности Shellsort" (PDF) . Журнал ACM . 47 (5): 905–911. arXiv : cs / 9906008 . CiteSeerX 10.1.1.6.6508 . DOI : 10.1145 / 355483.355488 .  
  24. ^ Vitányi, Пол (март 2018). «О средней сложности Shellsort» (PDF) . Случайные структуры и алгоритмы . 52 (2): 354–363. arXiv : 1501.06461 . DOI : 10.1002 / rsa.20737 .
  25. ^ Плэкстон, К. Грег; Пунен, Бьорн ; Суэль, Торстен (24–27 октября 1992 г.). Улучшенные нижние границы для Shellsort (PDF) . Ежегодный симпозиум по основам информатики (FOCS 1992) . 33 . Питтсбург, США. С. 226–235. CiteSeerX 10.1.1.43.1393 . DOI : 10.1109 / SFCS.1992.267769 . ISBN   978-0-8186-2900-6.
  26. ^ Плэкстон, К. Грег; Суэль, Торстен (май 1997 г.). "Нижние границы для Shellsort" (PDF) . Журнал алгоритмов . 23 (2): 221–240. CiteSeerX 10.1.1.460.2429 . DOI : 10.1006 / jagm.1996.0825 .  
  27. ^ Новоа, Мануэль III. "libc / stdlib / stdlib.c" . Проверено 29 октября 2014 года .
  28. ^ "kernel / groups.c" . Проверено 5 мая 2012 года .
  29. ^ Джулиан Сьюард. "bzip2 / blocksort.c" . Проверено 30 марта 2011 года .

Библиография [ править ]

  • Кнут, Дональд Э. (1997). «Метод Шелл». Искусство программирования. Том 3: Сортировка и поиск (2-е изд.). Ридинг, Массачусетс: Эддисон-Уэсли. С. 83–95. ISBN 978-0-201-89685-5.
  • Анализ Shellsort и связанных алгоритмов , Роберт Седжвик, Четвертый Европейский симпозиум по алгоритмам, Барселона, сентябрь 1996 г.

Внешние ссылки [ править ]

  • Анимированные алгоритмы сортировки: сортировка оболочки на обратном пути (архивировано 10 марта 2015 г.) - графическая демонстрация
  • Шеллсорт с пробелами 5, 3, 1 как венгерский народный танец