Пирамидальная сортировка
Пирамидальная сортировка — алгоритм сортировки, работающий в худшем, в среднем и в лучшем случае (то есть гарантированно) за Θ(n log n) операций при сортировке n элементов. Количество применяемой служебной памяти не зависит от размера массива (то есть, O(1)).
Может рассматриватъся как усовершенствованная Bubblesort, в которой элемент всплывает (min-heap) / тонет (max-heap) по многим путям....
Алгоритм
Сортировка пирамидой использует сортирующее дерево. Сортирующее дерево — это такое двоичное дерево, у которого выполнены условия:
- Каждый лист имеет глубину либо d либо d − 1, d — максимальная глубина дерева.
- Значение в любой вершине больше, чем значения её потомков.
Удобная структура данных для сортирующего дерева — такой массив Array, что Array[1] — элемент в корне, а потомки элемента Array[i] — Array[2i] и Array[2i+1].
Алгоритм сортировки будет состоять из двух основных шагов:
- Выстраиваем элементы массива в виде сортирующего дерева:
Array[i]>= Array[2i]
Array[i]>= Array[2i+1]
при 1 <= i < n/2.
Этот шаг требует O(n) операций.
- Будем удалять элементы из корня по одному за раз и перестраивать дерево. То есть на первом шаге обмениваем Array[1] и Array[n], преобразовываем Array[1], Array[2], … , Array[n-1] в сортирующее дерево.
Затем переставляем Array[1] и Array[n-1], преобразовываем Array[1], Array[2], … , Array[n-2] в сортирующее дерево. Процесс продолжается до тех пор, пока в сортирующем дереве не останется один элемент.
Тогда Array[1], Array[2], … , Array[n] — упорядоченная последовательность.
Этот шаг требует O(nlogn) операций.
Пример сортирующего дерева

Реализация быстрой сортировки на С++
03 | void iswap( int &n1, int &n2) |
13 | for ( int i = 0; i < n; ++i ) { a[i] = n - i; cout << a[i] << " " ; } |
23 | for ( int i = 0; i < n; i++ ) |
25 | if ( i * 2 + 2 + sh a[i * 2 + 2 + sh] ) ) |
27 | if ( a[i * 2 + 1 + sh] */ a[i * 2 + 2 + sh] ) |
29 | iswap( a[i + sh], a[i * 2 + 1 + sh] ); |
32 | else if ( a[i * 2 + 2 + sh] */ a[ i * 2 + 1 + sh]) |
34 | iswap( a[ i + sh], a[i * 2 + 2 + sh]); |
39 | else if ( i * 2 + 1 + sh a[ i * 2 + 1 + sh] ) |
41 | iswap( a[i + sh], a[i * 2 + 1 + sh] ); |
48 | if ( sh + 2 == n ) break ; |
51 | for ( int i = 0; i < n; ++i ) cout << a[i] << " " ; |
Достоинства и недостатки
Достоинства:
- Имеет доказанную оценку худшего случая O(nlogn).
- Требует всего O(1) дополнительной памяти (если дерево организовывать так, как показано выше).
Недостатки:
- Сложен в реализации.
- Неустойчив — для обеспечения устойчивости нужно расширять ключ.
- На почти отсортированных массивах работает столь же долго, как и на хаотических данных.
- На одном шаге выборку приходится делать хаотично по всей длине массива — поэтому алгоритм плохо сочетается с кэшированием и подкачкой памяти.
Вывод по пирамидальной сортировке
Сортировка слиянием при расходе памяти O(n) быстрее (O(n·logn) с меньшей константой) и не подвержена деградации на неудачных данных.
Из-за сложности алгоритма выигрыш получается только на больших n. На небольших n (до нескольких тысяч) быстрее сортировка Шелла.