CodeLAB
на главную карта сайта обратная связь

Популярные задачи:

#Работа с камерой. (35973 hits)
#Сравнение алгоритмов сортировки массива. (182546 hits)
#Сортировка Шелла, обший принцип. (145302 hits)
#Заполнение 2-го выпадающего списка (select) в соответствии с выбором в первом. (46426 hits)
#Передача данных из основного во всплывающее-popup окно через POST. (117054 hits)
#Подсветка синтаксиса. (31594 hits)
#Поверхностное клонирование. (27822 hits)
#Сравнение алгоритмов быстрой сортировки. (74087 hits)
#Простая геометрическая и текстовая анимация. (401118 hits)
#Рисование множества Мандельброта. (44542 hits)
#Сортировка вставкой. (112447 hits)
#Вычисление среднего, среднего отклонения, среднеквадратического отклонения и дисперсии заданной выборки. (46605 hits)
#Масштабирование, пропорциональное изменение размеров картинки. (101239 hits)
#"Липкие" окна. (32316 hits)
#Как посчитать одинаковые пары за 1 проход (самая быстрая версия!). (2293 hits)
#Последовательный поиск и его оптимизации. (44824 hits)
#Сохранение данных формы после перезагрузки через куки. (205005 hits)
#сортировка пузырьком. (153143 hits)
#Утилиты. (114620 hits)
#Наибольший общий делитель. (192882 hits)


Главная >> Каталог задач >> Сортировка >> Сортировка Шелла >> Сортировка Шелла, обший принцип

Сортировка Шелла, обший принцип

Aвтор:
Дата:
Просмотров: 145301
реализации(C++: 3шт...) +добавить

Сортировка Шелла это, по-сути, модификация схем сортировки других алгоритмов. Фактически для сортировки элементов используются другие алгоритмы, такие как: пузырьком, вставками, выбором и т.д. Но только эти алгоритмы применяются не ко всей исходной последовательности, а к ее частям.

Сначала в исходной последовательности сортируются между собой элементы, отстоящие друг от друга на расстоянии n/2 элементов, затем на расстоянии n/4 и т.д. до тех пор пока не получим 2 последовательности, элементы которых отстоят друг от друга на расстоянии 1-го элемента. После этого делаем сортировку этой полученной последовательсти выбранным методом и на выходе имеем уже полностью отсортированную последовательность.

Возникает вопрос: зачем же были предыдущие сортировки? Для того, чтобы расположить сортируемые элементы наиболее близко к своим положенным позициям. А в этом случае в последней сортировке по всей последовательности значительно сокращается количество перестановок.

Пример. Имеется последовательность [2, 3, 9, 2, 8, 4, 6, 8, 11, 12, 4, 6], n=12. Символом d - будем обозначать расстояние между сортируемыми элементами на каждом шаге (на первом шаге d = n/2, на втором d = d/2 и т.д.)

1 шаг. d = n/2 = 6. => Получаем 6 сортируемых групп(имеют одинаковый цвет):
[2, 3, 9, 2, 8, 4, 6, 8, 11, 12, 4, 6]
После сортировки в пределах каждой группы, имеем:
[2, 3, 9, 2, 4, 4, 6, 8, 11, 12, 8, 6]

2 шаг. d = d/2 = 3. => Получаем 2 сортируемых группы(имеют одинаковый цвет):
[2, 3, 9, 2, 4, 4, 6, 8, 11, 12, 8, 6]
После сортировки в пределах каждой группы, имеем:
[2, 3, 4, 2, 4, 6, 6, 8, 9, 12, 8, 11]

3 шаг. d = d/2 = 1(целочисленное деление) => заключительный шаг. Сортируем всю последовательность:
[2, 3, 4, 2, 4, 6, 6, 8, 9, 12, 8, 11] в итоге получим:
[2, 2, 3, 4, 4, 6, 6, 8, 8, 9, 11, 12]

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

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

Соответственно, получим:

 псевдокод: простая сортировка шелла пузырьком  ссылка
  1. d = n
  2. while d > 1
  3. d = d / 2 /* целочисленное */
  4. i = 0
  5. /* делаем 1 "пузырьковый" проход
  6. для элементов каждой группы */
  7. while (j = i + d) < n
  8. if x[i] > x[j]
  9. /* x[i] и x[j] меняем местами */
  10. swap(i, j)
  11. i++
  12.  
  13. BubbleSort()
  14. /* либо InsertSort(), либо SelectSort() */


При этом производительность алгоритма пропорциональна ~ O(n2), но количество перестановок по-сравнению с простыми методами вставкой, выбором или пузырьком - заметно сокращается. Дополнительная память - не используется(не считая счетчиков циклов и проч.).

Величина шага d - называется приращением и является важной характеристикой алгоритма Шелла. И выбор динамики уменьшения этой величины очень существенно сказывается на производительности алгоритма в целом, позволяя достигать пропорций от ~ O(n7/6) в лучшем случае до ~ O(n4/3) в худшем, о чем рассказывает следующая задача сортировка Шелла, оптимальный выбор приращений.

Реализации:

C++(3)   +добавить

1) Базовая сортировка Шелла, результирующая сортировка - вставками на C++, code #19[автор:this]
2) Базовая сортировка Шелла без результирующей сортировки на C++, code #24[автор:this]
3) shell_in_cpp_with_struct на C++, code #608[аноним:Aleksey Tarakanov]