Пирамидальная сортировка


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

Пусть имеется исходный массив n элементов а1 а2, а3, . . ., аn. Расположим эти элементы в виде двоичного дерева следующего вида (здесь важен порядок следования индексов элементов):

 


Подобное дерево называется пирамидой, если для всех элементов с индексами от 1 до n/2 выполняются следующие условия:

аi <= а2i и аi <= а2i+1

В частности, эти условия означают: а1 <= а2 и а1 <= а3; а2 <= а4 и а2 <= а5; а3 <= а6 и а3 <= а7; а4 <= а8 и а4 <= а9, и т.д.

Другими словами, в каждом элементарном поддереве значение в вершине этого поддерева меньше или равно значений в вершинах-потомках.

Пример двоичного дерева-пирамиды с 15-ю элементами:

Это – пирамида. Соответствующий массив: 15-25-20-30-40-22-33-50-60-45-47-44-28-55-66 Это – не пирамида (вершина 12 меньше 20)

 

Такие пирамиды иногда называют минимальными, в отличие от максимальных, где правило упорядоченности прямо противоположное.

Из примера видно, что пирамида НЕ является деревом поиска, т.к. строится по другим правилам.

Можно отметить следующие полезные свойства пирамиды:

· на вершине пирамиды всегда находится наименьший элемент во всем массиве (элемент а1), элемент а2 является наименьшим для левого поддерева, элемент а3 является наименьшим для правого поддерева и т.д.

· вершины, лежащие на самом нижнем уровне пирамиды всегда образуют из себя элементарные пирамиды, поскольку у них нет никаких потомков и их сравнивать не с кем

Пирамидальная сортировка включает два больших этапа:

· представление исходного массива в виде пирамиды

· последовательные удаления минимального элемента с вершины пирамиды с заменой его другим элементом

Реализация 1 этапа включает следующие шаги:

· условно разделяем исходный массив на две половины: левую с индексами от 1 до [n/2], и правую с индексами от [n/2]+1 до n (здесь [ ] обозначает целую часть); считаем пока, что левая половина образует верхнюю часть строящейся пирамиды, а правая – нижний слой терминальных вершин

· выбираем в левой половине последний элемент (его индекс m=[n/2]), а в правой половине – его непосредственных потомков (одного или двух, но хотя бы один будет обязательно) с индексом 2m и, возможно, 2m+1

· если потомков два, то выбираем из них наименьшего

· сравниваем элемент аm с наименьшим из потомков: если он больше, то меняем эти элементы в массиве местами для получения фрагмента пирамиды; в противном случае оставляем все без изменений, поскольку эти элементы уже образуют фрагмент пирамиды

· повторяем все описанные действия последовательно для оставшихся в левой части элементов справа налево, т.е. для аm-1, аm-2, аm-3, . . ., а1, при этом если происходит обмен между родительской вершиной и одним из потомков, выполняется проверка для новой вершины-потомка, т.к. она может иметь своих потомков, с которыми возможно потребуется ее обменять для выполнения условия пирамиды.

Тем самым, для каждого элемента массива находится его новое расположение в массиве таким образом, чтобы выполнялись условия пирамиды. Процесс определения нужного положения элемента в массиве-пирамиде называют просеиванием элемента через пирамиду. Построение пирамиды заканчивается после просеивания первого элемента а1. Пример для 15 элементов приведен в таблице (символ ~ обозначает перестановку элементов)

а1 а2 а3 а4 а5 а6 а7 а8 а9 а10 а11 а12 а13 а14 а15 сравнение и обмен
33 33> min(20, 50), 33~20
44< min(47, 66), нет
30 30> min(15, 55), 30~15
25 25> min(22, 60), 25~22
28 28>min(44, 20), 28~20
28<min(33, 50), нет
40 40>min(22, 15), 40~15
40 40>min(30, 55), 40~30
45 45>min(15, 20), 45~15
45 45>min(22, 30), 45~22
45 45>min(25, 60), 45~25
Пирамида построена

 

В худшем случае каждый шаг в просеивании очередного элемента требует двух сравнений: сначала сравниваются два потомка текущего элемента, а потом наименьший из них сравнивается с самим элементом. В примере для построения пирамиды потребовалось 11*2=22 сравнения и 9 пересылок.

Реализация второго этапа состоит в (n-1)-кратном повторении следующих действий:

· с вершины пирамиды забирается минимальный элемент а1

· на его место в вершину пирамиды помещается последний элемент в массиве, причем индекс этого последнего элемента на каждом шаге будет уменьшаться от аn до а2

· помещенный в вершину элемент просеивается через пирамиду обычным образом, при этом он встает на свое место, а в вершину пирамиды выталкивается минимальный из оставшихся в массиве элементов

· на последнем шаге в пирамиде останется один элемент (самый большой) и сортировка будет закончена

При этом возникает вопрос – куда девать снимаемые с вершины пирамиды элементы? Можно просто помещать их в конец массива на место элемента, размещаемого в вершине. В результате на месте исходного массива создается упорядоченный ПО УБЫВАНИЮ набор данных. При необходимости, алгоритм легко можно изменить для получения возрастающих последовательностей, если вместо минимальных использовать максимальные пирамиды.

 

а1 а2 а3 а4 а5 а6 а7 а8 а9 а10 а11 а12 а13 а14 а15 сравнение и обмен
15 = min, 15~50
50>min(22, 20), 50~20
50>min(44, 28), 50~28
50>33, 50~33
20 = min, 20~50
50>min(22, 28), 50~22
50>min(25, 30), 50~25
50>min(45, 60), 50~45
22 = min, 22~66
66>min(25, 28), 66~25
66>min(45, 30), 66~30
66>min(40, 55), 66~40
25 = min, 25~47
47>min(30, 28), 47~28
47>min(44, 33), 47~33
28 = min, 28~55
55>min(30, 33), 55~30
55>min(45, 40), 55~40
55<66, 30 = min, 30~66
66>min(40, 33), 66~33
66>min(44, 47), 66~44
33 = min, 33~60
60>min(40, 44), 60~40
60>min(45, 55), 60~45
60>50, 60~50
40 = min, 40~60
60>min(45, 44), 60~44
60>min(66, 47), 60~47
44 = min, 44~60
60>min(45, 47), 60~45
60>min(50, 55), 60~50
45 = min, 45~66
66>min(50, 47), 66~47
47 = min, 47~55
55>min(50, 66), 55~50
55<60, 50 = min, 50~60
60>min(55, 66), 60~55
55 = min, 55~66
66>60, 66~60
60 = min, 60~66
сортировка закончена

 

В данном примере выполнено 51 сравнение и 40 пересылок, что вместе с этапом построения пирамиды дает 73 сравнения и 49 пересылок.

В целом, данный метод с точки зрения трудоемкости имеет типичное для улучшенных методов поведение: довольно высокая трудоемкость для небольших n, но с ростом n эффективность метода растет. При больших n метод в среднем немного уступает быстрой сортировке и имеет оценку порядка (n*log 2 n)/2. Единственное, в чем он превосходит быструю сортировку, так это поведение на аномальных входных данных, когда быстрая сортировка перестает быть “быстрой”, а пирамидальная сохраняет свою трудоемкость порядка O(n*log 2 n). В [4] указывается, что пирамидальную сортировку выгодно использовать в том случае, когда требуется не провести полную сортировку большого набора данных, а лишь найти несколько (причем – немного) первых наименьших элементов.

Необходимо отметить, что понятие пирамидального дерева имеет и самостоятельное значение, и часто используется для решения других задач, не связанных с сортировкой массивов, например – для эффективной реализации приоритетных очередей [4].

В заключение рассмотрим вопросы программной реализации пирамидальной сортировки. Поскольку оба этапа алгоритма основаны на повторении одинаковых действий по просеиванию элементов, удобно оформить просеивание в виде вспомогательной процедуры.

Procedure Sito (al, ar : word);

var i, j : word;

x : <описание элемента массива>;

Begin

i := al; j := 2*al; x := mas[al];

if (j < ar) and (mas[j + 1] < mas [j] ) then j := j + 1;

while (j <=ar) and (mas[j] < x) do

Begin

mas [i] := mas [j]; i :=j; j :=2*j;

if (j < ar) and (mas[j + 1] < mas[j]) then j := j + 1;

end;

mas[i] := x;

end;

Тогда основная программа будет лишь включать два последовательных цикла – один для построения пирамиды, второй – для снятия с вершины наименьшего элемента и просеивания нового вершинного элемента.

left := (n div 2) + 1; right := n;

{определение границ правой половины массива}

while left > 1 do

begin {цикл построения пирамиды}

left := left – 1; Sito (left, right);

end;

while right > 1 do (цикл сортировки}

Begin

temp := mas[1]; mas[1] := mas[right]; mas[right] := temp;

right := right – 1; Sito (left, right);

end;

 



Дата добавления: 2020-07-18; просмотров: 456;


Поиск по сайту:

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.022 сек.