
- •Сортировки
- •Введение
- •Формулировка задачи сортировки
- •Простейшие методы сортировки
- •Алгоритм линейной сортировки (метод прямого выбора)
- •1 Способ 2 способ
- •Алгоритм сортировки обменом (метод "Пузырька")
- •Усовершенствованная "пузырьковая" сортировка
- •"Шейкер" - сортировка
- •Сортировка подсчетом
- •Алгоритм сортировки вставками (метод прямого включения)
- •Размещение путем сравнения и обмена (просеивание)
- •Размещение путем поиска места и вставки
- •Более сложные и более эффективные методы сортировки
- •Алгоритм сортировки Шелла (метод h-сортировки)
- •Обменная сортировка с разделением (сортировка Хоара)
- •Сортировка методом слияний
- •Простое слияние
- •Естественное двухпутевое слияние
- •Рекурсивный алгоритм слияния
- •Слияние списков
- •Алгоритм сортировки бинарными вставками
- •Сортировка с помощью двоичного включения
- •Лексикографическая сортировка
- •Топологическая сортировка
- •Поразрядная сортировка
- •Пирамидальная сортировка
- •Рекурсивная сортировка
- •Сравнительная характеристика методов сортировки
- •Классификация задач с применением сортировок
- •1. Задачи заполнения
- •2. Задачи анализа
- •3. Задачи поиска
- •4. Задачи перестановки
- •Литература
Пирамидальная сортировка
Принципы пирамидальной сортировки будет проще понять, если рассмотреть два жизненных примера: организацию турнирной таблицы и корпоративную систему выдвижения.
1. Организация турнирной таблицы происходит следующим образом: в первом туре участники разбиты на пары и играют между собой, победители проходят в следующий тур и играют между собой и т.д. В полуфинале участвует 4 участника, в финале 2 и определяется победитель.
Теперь, чтобы определить второго по силе участника, надо вывести из турнира сильнейшего и разыграть турнир заново. Продолжая эту процедуру, найдем третьего по силе, четвертого и т.д.
Рассмотрим организацию турнира на примере «участников» - элементов массива (5, 2, 8, 9, 3, 1, 7. 2).
|
|
|
|
|
|
|
9 |
|
|
|
|
|
|
|
|||||||
|
|
|
9 |
|
|
|
|
|
|
|
7 |
|
|
|
|||||||
|
5 |
|
|
|
|
9 |
|
|
|
3 |
|
|
|
|
7 |
|
|||||
5 |
|
|
2 |
|
8 |
|
|
9 |
|
3 |
|
|
1 |
|
7 |
|
|
2 |
Победителем является «участник» 9. Выведем его из турнира, заменив на «чрезвычайно слабого игрока» -.
|
|
|
|
|
|
|
8 |
|
|
|
|
|
|
|
|||||||
|
|
|
8 |
|
|
|
|
|
|
|
7 |
|
|
|
|||||||
|
5 |
|
|
|
|
8 |
|
|
|
3 |
|
|
|
|
7 |
|
|||||
5 |
|
|
2 |
|
8 |
|
|
- |
|
3 |
|
|
1 |
|
7 |
|
|
2 |
Победителем является «участник» 8. Выведем его из турнира, заменив на «чрезвычайно слабого игрока» -.
|
|
|
|
|
|
|
7 |
|
|
|
|
|
|
|
|||||||
|
|
|
5 |
|
|
|
|
|
|
|
7 |
|
|
|
|||||||
|
5 |
|
|
|
|
- |
|
|
|
3 |
|
|
|
|
7 |
|
|||||
5 |
|
|
2 |
|
- |
|
|
- |
|
3 |
|
|
1 |
|
7 |
|
|
2 |
|
|
|
|
|
|
|
5 |
|
|
|
|
|
|
|
|||||||
|
|
|
5 |
|
|
|
|
|
|
|
3 |
|
|
|
|||||||
|
5 |
|
|
|
|
- |
|
|
|
3 |
|
|
|
|
2 |
|
|||||
5 |
|
|
2 |
|
- |
|
|
- |
|
3 |
|
|
1 |
|
- |
|
|
2 |
И т.д. Таким образом, происходит сортировка посредством выбора из дерева – выбирается максимальный элемент, находящийся в корне дерева.
2. Корпоративная система выдвижения заключается в следующем: из группы простых исполнителей на верхний уровень поднимаются лучшие (например, из группы программистов выдвигаются старшие программисты). Среди старших программистов отбирают руководителей лаборатории. Среди руководителей лаборатории отбирают руководителей отделов и т.д. При этом, когда участник поднимается с самого нижнего уровня, его заменяют «человеком с улицы» (-), а если выдвижение идет с очередного уровня, то его заменяют на лучшего из его подчиненных.
|
|
|
|
|
|
|
9 |
|
|
|
|
|
|
|
|||||||
|
|
|
8 |
|
|
|
|
|
|
|
7 |
|
|
|
|||||||
|
5 |
|
|
|
|
- |
|
|
|
3 |
|
|
|
|
2 |
|
|||||
- |
|
|
2
|
|
- |
|
|
- |
|
- |
|
|
1 |
|
- |
|
|
- |
В результате получим корпоративную пирамиду, где каждый стоит на своем уровне компетентности.
|
|
|
|
|
|
|
9 |
|
|
|
|
|
|
|
|||||||
|
|
|
8 |
|
|
|
|
|
|
|
7 |
|
|
|
|||||||
|
5 |
|
|
|
|
- |
|
|
|
3 |
|
|
|
|
2 |
|
|||||
- |
|
|
2 |
|
- |
|
|
- |
|
- |
|
|
1 |
|
- |
|
|
- |
Интуитивно второй способ более удобен – он позволяет избежать лишних сравнений - с -, на которые мы будет то и дело натыкаться в турнирной таблице на поздних стадиях.
Пронумеруем теперь элементы пирамиды по уровням сверху-вниз и слева-направо:
|
|
|
|
|
|
|
X1 |
|
|
|
|
|
|
|
|||||||
|
|
|
X2 |
|
|
|
|
|
|
|
X3 |
|
|
|
|||||||
|
X4 |
|
|
|
|
X5 |
|
|
|
X6 |
|
|
|
|
X7 |
|
|||||
X8 |
|
|
X9 |
|
X10 |
|
|
X11 |
|
X12 |
|
|
X13 |
|
X14 |
|
|
X15 |
Заметим, что отцом k-го узла является узел с номером (k div 2), а потомками - узлы с номерами 2k и 2k+1.
В пирамиде выполнено условие
|
|
|
Xk div 2 |
|
||
|
Xk |
|
|
|
|
|
X2k |
|
|
X2k+1 |
|
Очевидным недостатком рассмотренного метода является большое число бесполезных дыр, содержащих -. Было бы очень хорошо организовать пирамиду на N ячейках (в нашем случае на 8, а не на 15).
Эта цель была реализована Дж. У. Дж. Уильямсом (John William Joseph Williams) в 1964 году, разработавшим алгоритм пирамидальной сортировки (heap-sort). В дальнейшем сортировку развивал Р.Флайд.
Будем называть массив X1 , X2 , X3 … Xn пирамидой, если выполнено условие:
Xj div 2 Xj , при 1 j div 2 < j N.
Тогда X1 X2, X1 X3, X2 X4, X2 X5, и т.д. В частности, наибольший ключ лежит на вершине пирамиды: X1 = max (X1 , X2, … Xn).
Если удастся каким-либо образом преобразовать массив в пирамиду, то можно будет забрать корень, обменяв его с последним элементов, а затем, уменьшив размер кучи на единицу, воспользоваться нисходящей процедурой построения кучи для корня: на место корня переместить вверх наибольшего из его потомков, затем переместить вверх наибольшего из потомков последнего и т.д.
Нисходящая процедура для k-го элемента кучи, состоящей из Count элементов, выглядит следующим образом:
Procedure downheap(k: integer);
Var i, j, t: integer;
Begin
T:=x[k];
While k<=Count div 2 do
Begin
J:=k+k;
If j<Count then if x[j] < x[j+1] then j:=j+1;
If t >= x[j] then break;
X[k]:= x[j]; k:=j;
End;
X[k]:=t;
End;
Применим нисходящую процедуру ко всем элементам, начиная с N div 2. А затем, получив кучу, заберем корень, обменяв его с последним элементом, и применим нисходящую процедуру к корню.
Например, для массива 5, 2, 8, 9, 3, 1, 7, 2 алгоритм будет выглядеть следующим образом:
Расположим массив в кучу:
|
|
|
|
|
|
5 |
|
|
|
|
|
|
||||||
|
|
|
2 |
|
|
|
|
|
|
|
8 |
|
|
|
||||
|
9 |
|
|
|
|
3 |
|
|
|
1 |
|
|
|
|
7 |
|
||
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Применим нисходящую процедуру к среднему элементу 9, получим массив 5, 9, 8, 2, 3, 1, 7, 2.
|
|
|
|
|
|
5 |
|
|
|
|
|
|
||||||
|
|
|
9 |
|
|
|
|
|
|
|
8 |
|
|
|
||||
|
2 |
|
|
|
|
3 |
|
|
|
1 |
|
|
|
|
7 |
|
||
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Применим процедуру к элементам 8, 9 и 5, получим массив 9, 5. 8, 2. 3, 1, 7, 1 - это куча.
|
|
|
|
|
|
9 |
|
|
|
|
|
|
||||||
|
|
|
5 |
|
|
|
|
|
|
|
8 |
|
|
|
||||
|
2 |
|
|
|
|
3 |
|
|
|
1 |
|
|
|
|
7 |
|
||
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Обменяем местами корень 9 и последний элемент 2, получим массив 2, 5. 8, 2, 3, 1, 7, 9. При этом 9 стоит уже на своем месте.
|
|
|
|
|
|
2 |
|
|
|
|
|
|
||||||
|
|
|
5 |
|
|
|
|
|
|
|
8 |
|
|
|
||||
|
2 |
|
|
|
|
3 |
|
|
|
1 |
|
|
|
|
7 |
|
||
9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Уменьшим размер кучи на 1 и применим нисходящую процедуру к корню 2, получим массив 8, 5, 7, 2, 3, 1, 2, 9.
|
|
|
|
|
|
8 |
|
|
|
|
|
|
||||||
|
|
|
5 |
|
|
|
|
|
|
|
7 |
|
|
|
||||
|
2 |
|
|
|
|
3 |
|
|
|
1 |
|
|
|
|
2 |
|
||
9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Обменяем корень с последним элементом, получим массив 2, 5, 7, 2, 3, 1, 8, 9. И т.д.
Procedure HeapSort(var x: vector);
Var k, t : integer;
Count; integer;
Begin
Count:=N;
For k:=N div 2 downto 1 do Downheap(k);
Repeat
T:=x[1]; x[1]:=x[Count]; x[Count]:= t;
Dec(count);
HeapDown(1);
Until Count <=1;
End;
Таким образом, алгоритм пирамидальной сортировки состоит из двух этапов:
1. Построение пирамиды из данного массива на том же месте. Делается это процедурой sift.
2. Сортировка пирамиды. Меняются значениями концевые элементы пирамиды, и она укорачивается справа на один элемент (он будет вершиной пирамиды). Полученный укороченный массив уже не может быть пирамидой, поэтому, применяя процедуру sift, делаем его пирамидой. Повторяя этот этап n-1 раз, отсортируем массив в a[n]<=a[n-1]<=...a[1].
Время работы пирамидальной сортировки имеет порядок NlogN. Пирамидальная сортировка сравнима с сортировкой Шелла или быстрой сортировкой, причем вспомогательной памяти используется мало. С ростом N пирамидальная сортировка превзойдет по скорости сортировку Шелла, но никогда не станет лучше быстрой сортировки. Однако, в отличие от быстрой сортировки ее наихудший случай не намного хуже среднего.