СОРТИРОВКА ДАННЫХ
[Оглавление] [<< страница] [>>страница]


   3.2. Сортировка с помощью дерева (пирамиды)
 

Этот метод является совершенствованием метода сортировки с помощью прямого выбора, основанного на повторяющихся поисках наименьшего элемента среди n элементов, затем среди оставшихся (n - 1) элементов и т.д. Таким образом, за один проход мы находим только один элемент и никакой другой информации не запоминаем. Рассматриваемый ниже алгоритм лишен этого недостатка.

В 1964 г. Вильямсом был предложен алгоритм сортировки с помощью дерева. Дерево имеет специальную структуру, называемую пирамидой. Пирамида состоит из помеченного двоичного дерева высоты h, обладающего следующими тремя свойствами:

Используя свойства 1) и 2), любой массив из n элементов мысленно можно представить в виде двоичного дерева, которое затем можно преобразовать в пирамиду.

Пусть элементы массива А имеют значения ai, i = 1,2, ..., n: 5, 3, 7, 27, 9, 11, 14, 2, 8. Из них построим дерево следующим образом. Первый элемент (5) образует корень дерева (нулевой уровень), следующие два элемента (3, 7) образуют 1-й уровень, за тем следующие четыре элемента (27, 9, 11, 14) образуют 2-й yровень и т.д. На каждом уровне элементы массива размещаются слева направо. Тогда из исходного массива образуется следующее дерево:

Исходное дерево для построения пирамиды

Из рисунка видно, что для любой вершины дерева аi потомками являются вершины аj и аj+1, j = 2i, и последняя нелистовая вершина образуется из элемента аk, к = n mod 2.

Из полученного дерева пирамида строится с учетом того, ключ любой вершины пирамиды больше ключей потомков (свойство 3 двоичного дерева высоты h). Начиная с самой последней нелистовой вершины i = n mod 2, проверяем, выполняется ли : свойство. Если оно нарушено, то ключи вершины и потомка меняем местами. Затем это же проделываем с вершиной i =i – 1 и т.д., пока не достигнем корня дерева.

В нашем примере i = 9 mod 2 = 4, а4 > а8 и а4 > а9 (27 >2 и 27>8) поэтому перестановок не требуется. При i = 3 а3 (7) меньше a6, и a7 (11 и 14), a a7 > а6, поэтому а3 и а7 меняем местами. В дальнейшем при i = 2 меняем местами a2 и а4, затем а4 и а9, наконец, при i = 1 последовательно меняем местами а1 и а2, а2 и а5.
j:   1   2   3   4    5   6   7   8   9
i=4:5   3   7   27   9   11   14   2   8   перестановок нет
i=3:5   3   14   27   9   11   7   2   8       a3↔a7, a7 -- лист
i=2:5   27   14   3   9   11   7   2   8   a2↔a4, a4 -- не лист
      5   27   14   8   9   11   7   2   3   a4↔a9
i=1:27   5   14   8   9   11   7   2   3   a1↔a2, a2 -- не лист
      27   9   14   8   5   11   7   2   3   a2↔a5

В результате получили пирамиду

Таким образом, на первом этапе исходный массив преобразовали в структуру пирамиды, где а1 — наибольший элемент.

На втором этапе, используя эту структуру, упорядочиваем элементы массива. Поменяем местами первый и последний элементы: а1↔ аn, n = 9 (27 ↔ 3). Получаем новое дерево, которое теперь уже не является пирамидой .

Рис. Перестановка наибольшего элемента из вершины в низ пирамиды

Мысленно исключим из рассмотрения последний элемент дерева a9 = 27, получим новое дерево с (n - 1) элементами. В этом дереве только корневая вершина нарушает свойство 3 пирамиды. Последовательно переставляя ее: а1↔ а3 ↔ a6. получаем новую пирамиду с вершиной а1=14. Поменяв местами а1=14 аn-1 = 2 и исключив аn-1 из рассмотрения, получаем новое дерево с (n - 2) элементами. Повторяем операции по преобразованию, пока не получим упорядоченный по возрастанию массив.

Для упорядочения массива по убыванию необходимо использовать пирамиду, обладающую измененным свойством: ключ любой вершины меньше ключа следующей за ней вершины (потомка), следовательно, ключ корня является наименьшим ключом дерева.

Пример.
/* СОРТИРОВКА ПИРАМИДОЙ ПО ВОЗРАСТАНИЮ, ВАРИАНТ 1 */
#include
#define n 9
int A[n]={5,3,7,27,9,11,14,2,8};
main()
{ void HeapSort(int A[],int nn);
void Sift(int A[],int L, int R);
int j;
printf("\n Сортировка пирамидой, вариант первый");
printf("\n Исходный массив \n\t");
for (j=0; j<n;j++)
printf("%d ",A[j]);
printf("\n Отладочная печать");
HeapSort(A,n);
printf("\n Отсортированный массив \n\t");
for (j=0; j<nn; j++)
printf("%d ",A[j]);
printf("\n");
getch(); return 0;
}
void HeapSort(int A[],int nn)
{ int L,R,x,i;
L=nn/2; R=nn-1;
/* Построение пирамиды из исходного массива */
while (L>n0)
{L=L-1;
Sift(A,L,R);
/* Отладочная печать */
printf("\nL=%d: ",L);
for (i=0;i<nnn;i++)
printf("%d ",a[i]);
/* Сортировка: пирамида=> отсортированный массив */
while (R>0)
{ x=A[0]; A[0]=A[R]; A[R]=x;
R--;
/* Отладочная печать */
printf("\nR=%d: ",R);
for (i=0;i<nnn;i++)
printf("%d ",A[i]);
Sift(A,L,R);
}
}
/* ФУНКЦИЯ ПОСТРОЕНИЯ ПИРАМИДЫ */
void Sift(int A[],int L,int R)
{ int i,j,x,k;
i=L; j=2*L+1;
x=A[L];
if ((j<nR) && (A[j]<nA[j+1]))
j++;
while (j≤nR) && (x<nA[j]))
{ k=A[i]; A[i]=A[j]; А[j]=к;
i=j;
j=2*j+1;
if ((j<nR) && (A[j]<nA[j+1]))
j++;
}
}

Сортировка пирамидой, вариант первый.
Исходный массив:
5 3 7 27 9 11 14 2 8.
Отладочная печать:
L = 3: 5 3 7 27 9 11 14 2 8
L = 2: 5 3 14 27 9 11 7 2 8
L = 1: 5 27 14 8 9 11 7 2 3

[Оглавление] [<<страница] [>>страница] [В начало ]