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

ВЫБОР НАИМЕНЬШЕГО КЛЮЧА

 

Рис. 3.7

Наша очередная задача — найти способы эффективной организации информации, обрабатываемой на каждом шаге.

Во-первых, желательно избавиться от необходимости в «дырах»; во-вторых, нужно найти способ представить дерево из п элементов в виде массива.

Метод пирамидальной сортировки, изобретенный Д. Уилльямсом, является улучшением традиционных сортировок с помощью дерева [1, 3, 9, 10, 13]. Пирамидой называется двоичное дерево такое, что

a[i] <a[2*i]; a[f\<a[2*i+ 1]. Отсюда следует, что а[\] — минимальный элемент пирамиды.

Сначала расположим исходный массив в пирамиде, а затем пересортируем элементы. Это и есть общая идея пирамидной сортировки (рис. 3.8).


    а[1]    
< а[4] 2] ч а[51   а < а[6] [3] \ а[7]

Рис. 3.8

Выполнение алгоритма разбивается на два этапа.

I этап. Построение пирамиды.Определяем правую часть дерева, начиная с п/2 + 1 (нижний уровень дерева). Берем элемент левее этой части массива и просеиваем его сквозь пирамиду по пути, где находятся меньшие его элементы, которые одновременно поднимаются вверх; из двух возможных путей выбираете путь через меньший элемент.

Массив для сортировки:

24, 3, 15, 20, 52, 6.

Расположим элементы в виде исходной пирамиды; номер элемента правой части (6/2 + 1) = 4. Просеиваемый элемент имеет номер 3 (рис. 3.9).

 

     
3' У N   У

Рис. 3.9

Результат просеивания элемента 15 через пирамиду показан ниже (рис. 3.10).

 

   
  3f У
           

Рис. 3.10 155


Следующий просеиваемый элемент 31; затем — 24 (рис. 3.11).

 

               
  24*  
             
     
  ^ \   гГ  
       
             
   
             
     
    f X N   /  
       
               

Рис. 3.11

Разумеется, полученный массив еще не упорядочен. Однако, процедура просеивания является основой для пирамидальной сортировки. В итоге просеивания наименьший элемент оказывается на вершине пирамиды. Оформим функцию просеивания элемента с индексом left сквозь часть пирамиды left+\, ..., right.

II этап. Сортировка на построенной пирамиде.Берем последний элемент массива в качестве текущего. Меняем первый элемент массива (верхний элемент пирамиды, он наименьший) и текущий местами. Текущий элемент (он теперь первый) просеиваем сквозь п-\ элементную пирамиду. Затем берем предпоследний элемент и т.д.

1. Исходной является построенная ранее пирамида. Меняем местами элементы 6 и 24: элемент 6 встал на место (рис. 3.12).

Просеиваем элемент 24 сквозь пирамиду, не трогая элемента 6. В итоге просеивания на вершине окажется 15 — наименьший элемент из оставшейся части массива.


Рис. 3.12

2. Теперь уже два элемента на месте. Продолжим процесс (рис. 3


Рис. 3.13

Рис. 3.14


3. Продолжим процесс. В итоге массив будет отсортирован по убыванию (рис. 3.14).


Алгоритм пирамидальной сортировки

void heapSort(int numbers[], int array_size)

{

int i, temp;

for (i = (array_size / 2)-l; i >= 0; i--) siftDown(numbers, i, array_size);

for (i = array_size-l; i >= 1; i--)

{

temp = numbers[0];

numbers[0] = numbers[i];

numbers[i] = temp;

siftDown(numbers, 0, i-1); } }

void siftDown(int numbers[], int root, int bottom)

{

int done, maxChild, temp;

done = 0;

while ((root*2 <= bottom) && (!done))

{

if (root*2 == bottom)

maxChild = root * 2; else if (numbers[root * 2] > numbers[root * 2 + 1\

maxChild = root * 2; else

maxChild = root * 2 + 1;

if (numbers[root] < numbers[maxChild])

{

temp = numbers[root];

numbers[root] = numbers[maxChild];

numbers[maxChild] = temp;

root = maxChild;

} else

done = 1; }


Анализ алгоритма [3].Несмотря на некоторую внешнюю сложность, пирамидальная сортировка является одной из самых эффективных. Алгоритм сортировки эффективен для больших п. В худшем случае требуется и-log п шагов, сдвигающих элементы. Среднее число перемещений примерно равно (п/2)-log n, и отклонения от этого значения относительно невелики.