Изменения

Перейти к: навигация, поиск

Smoothsort

195 байт убрано, 23:53, 15 июня 2015
м
Примечание
'''Плавная сортировка''' (англ. Smooth sort) {{---}} алгоритм сортировки, модификация [[Сортировка кучей|сортировки кучей]], разработанный Э. Дейкстрой. Как и пирамидальная сортировка, в худшем случае работает за время <tex> \Theta(N\log{N}) </tex>. Преимущество плавной сортировки в том, что её сложность время работы приближается к <tex dpi = 120> O(N) </tex>, если входные данные частично отсортированы, в то время как у сортировки кучей сложность всегда одна, независимо время работы не зависит от состояния входных данных.
==Основная идея==
{{Утверждение
|statement= Любое натуральное число можно представимо в виде суммы из <tex dpi = 120> O(\log{N}) </tex> различных чисел Леонардо.
}}
При конструировании последовательности куч будем по очереди вставлять в конец новые элементы, а при получении отсортированного массива {{---}} удалять максимальный элемент из последовательности. Следовательно, нам необходимы две операции: увеличение последовательности куч путём добавления элемента справа (будем считать, что в начале последовательности располагаются кучи максимального размера) и уменьшение путём удаления крайнего правого элемента (корня последней кучи), с сохранением состояния кучи и последовательности.
Чтобы быстро обращаться к кучам, будем хранить список их длин. Зная индекс корня некоторой кучи и её длину, можно найти индекс корня соседней кучи слева от неё. Чтобы искать индексы детей вершины, надо воспользоваться свойством кучи Леонардо, что левым поддеревом является <tex dpi = 120> (n - 1) </tex>-ая, а правым является <tex dpi = 120> (n - 2) </tex>-ая куча Леонардо. Для хранения списка длин куч придется выделить <tex dpi = 120> O(\log{N}) </tex> дополнительной памяти.
===Вставка элемента===
#* Пока размер текущей кучи больше <tex dpi = 120> 1 </tex>, и значение корня любой из куч-потомков больше значения корня текущей кучи:
#** Меняются местами наибольший по значению корень кучи-потомка и текущий корень. Куча-потомок становится текущей кучей.
Операция просеивания значительно упрощена благодаря использованию чисел Просеивание в куче Леонардосильно упрощено, так как каждая куча либо будет одноэлементной, иметь либо будет иметь двух потомков, либо ноль. Нет нужды беспокоиться об отсутствии одной из куч-потомков.
Так как в последовательности <tex dpi = 120> O(\log{N}) </tex> куч, то модификация сортировки вставками будет работать за <tex dpi = 120> O(\log{N}) </tex>. Просеивание тоже выполняется за <tex dpi = 120> O(\log{N}) </tex>, тогда в итоге операция вставки выполняется за:
===Восстановление свойств последовательности===
Пусть нам надо восстановить инвариант последовательности куч. Будем считать, что функции '''''<tex>\mathrm{prev''''' }</tex> (возвращает индекс корня ближайшей слева кучи), '''''<tex>\mathrm{left''''' }</tex> (возвращает индекс левого сына), '''''<tex>\mathrm{right''''' }</tex> (возвращает индекс правого сына) уже реализованы. В функцию '''''<tex>\mathrm{ensureSequence''''' }</tex> передается индекс корня кучи, с которой начинаем восстановление.
<code>
'''function''' ensureSequence(i: '''int'''):
===Построение последовательности===
Последовательность куч получается последовательной вставкой при вставке элементов массива по очереди в конецэту самую последовательность. Получаем время работы <tex dpi = 120> O(N \log{N}) </tex>.
===Получение отсортированного массива===
Так как <tex dpi = 120> O(N) </tex> выполняется удаление максимального элемента из последовательности, то вся эта операция выполняется за <tex dpi = 120> O(N\log{N}) </tex>. Следовательно, сортировка в худшем случае выполняется за то время работы сортировки составляет <tex dpi = 120> O(N\log{N}) </tex>.
===Лучший случай===
Однако если подать на вход плавной сортировке уже отсортированный массив, асимптотика будет составлять <tex dpi = 120> O(N) </tex>. Дело в том, что:
*Операция добавления элемента последовательности на таком примере будет выполняться за <tex dpi = 120> O(1) </tex>, из-за того, что в конец будет добавляться максимальный элемент и просеивание будет сразу останавливаться.
*Операция получения и удаления максимального элемента будет так же также выполняться за <tex dpi = 120> O(1) </tex>, потому что в силу построения в корнях куч-детей будут новые максимальные элементы и следовательно восстановление свойства последовательности закончится на просмотре корня соседней кучи.
В итоге на таком примере получается асимптотика <tex dpi = 120> O(N) </tex>.
===Недостатки===
* не является устойчивой,
* требует <tex dpi = 120> O(\log{N}) </tex> дополнительной памяти для хранения длин куч в последовательности. Однако с помощью некоторых модификации модификаций расходы на дополнительную память можно получить сократить до <tex dpi 120> O(1) </tex> дополнительной памяти.
===Связь с быстрой сортировкой===
На практике, когда реализуют алгоритм быстрой сортировки, пытаются улучшить асимптотику в худшем случае. Для этого заводится некоторый лимит глубины рекурсии, при превышении которого запускают другую сортировку. Так реализована стандартная сортировка в стандартной библиотеке языка С++. Часто при превышении порога глубины рекурсии используют сортировку кучей. Замена неё на плавную сортировку могла бы улучшить время работы на некоторых тестах, так как после нескольких итераций быстрой сортировки массив окажется почти отсортированным, а на таких массивах время работы плавной сортировки приближается к линейному. Хотя итоговой линейной асимптотики достичь всё равно не получится по [[Теорема о нижней оценке для сортировки сравнениями | теореме о нижней оценке]].
==См. также==
* [[Быстрая сортировка|Быстрая сортировка]]
==ПримечаниеПримечания==
<references />

Навигация