Сортировка - турнир с выбыванием


Добавил:DMT
Дата создания:23 апреля 2008, 22:25
Дата обновления:23 апреля 2008, 22:26
Просмотров:10304 последний позавчера, 19:32
Комментариев: 0

Действия напоминают процесс разыгрывания некоторого турнира, где его участники состязаются друг с другом для определения наилучшего игрока.

Рассмотрим, например, последовательность из восьми чисел: 25,57,48,37,20,92,86,33. Предположим, что при встрече двух чисел побеждает большее. Тогда после проведения встреч мы получим следующее дерево (рис), отображающее ход турнира.

Расположим узлы этого дерева в массиве, состоящем в данном случае из 15 элементов. В общем случае исходный массив состоит из n ? size =2 k чисел и количество его элементов n дополняется до 2 k добавлением достаточно малых чисел. Мы будем добавлять числа, равные -32768. В общем случае для хранения узлов турнирного дерева достаточно массива, состоящего из 2 k +1 -1 чисел. Определим его как

int tree [2* size ];

Нумерация элементов этого массива будет начинаться с 1 , элемент tree [0] не используется, поэтому число его элементов равно 2 k +1 =2 size .

Исходный сортируемый массив расположим в узлах

tree[size], tree[size+1], ..., tree[2*size-1].

Каждый элемент массива tree будет рассматриваться как узел дерева. Отцом элемента tree [ i ] является элемент tree [ i /2] ( i /2 - целая часть дроби ) , а сыновьями – элементы tree [2 i ] и tree [2 i +1].

В узлах дерева tree [ i ] при 1 ? i ? size -1 запишем индекс большего из сыновей.

В рассматриваемом примере в узлах дерева будут записаны значения, как показано на рис.

Первый этап сортировки завершается построением дерева, аналогичного приведенному на рис.и вычислением значений в узлах.

После первого этапа известен наибольший элемент. В нашем примере этим элементом будет tree [13]=92. Далее будем выявлять наибольший среди оставшихся. Он будет наибольшим среди тех, которые сравнивались с числом tree [13]. Поэтому для его нахождения достаточно сравнить между собой те элементы, которые сравнивались с tree [13] , эти элементы будут являться сыновьями узлов, в которых значения равны 13 . Следовательно, нужно сначала изменить tree [6]=12 , а затем, на протяжении единственного пути, соединяющего tree [6] и tree [1] , сравнивать сыновей узлов tree [ i ] , изменяя счетчик i с помощью операции i = i /2 перехода к индексу отцовского узла.

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

Таким образом, второй этап будет состоять из цикла, в котором k пробегает значения k = n , n -1,...,2 . Цикл состоит из операции x [ k ]= tree [ tree [1]] присваивания x [ k ] наибольшему среди рассмотренных элементов («участвующих во встречах») и переупорядочивания дерева вдоль пути, соединяющего узел i = tree [1] с корнем. После завершения цикла x [1] будет равен tree [ tree [1]]. Получим отсортированный массив x [1], x [2],..., x [ n ] .

В нашем примере после первой итерации цикла дерево преобразуется в дерево, показанное на рис. Значение узла 6 изменяется на 12, в узле 3 – на 14, в узле 1 – на 14.

Разработаем подпрограмму void Tourtament ( int n , int * x ) сортировки описанным методом. Она будет состоять из двух частей, соответствующих первому и второму этапам алгоритма «турнир с выбыванием».

В первой части вычисляется наименьшая степень двойки size =2 k такая, что n ? size . А затем вызывается подпрограмма инициализации

void Initialize(int n,int size,int small,int *x,int *tree);

которая заполняет элементами массива x узлы tree [ size ], tree [ size +1], ..., tree [ size + n -1] и дополняет их числами small  = -32768 , а потом проводит «турнир», в результате которого выявляется наибольший элемент, и индекс этого элемента записывается в tree [1].

Вторая часть состоит из цикла

for ( k = n ; k >1; k --)

{

i = tree [1]; //индекс наибольшего числа

x [ k ]= tree [ i ]; //запись наибольшего числа в массив

tree [ i ]= small ; //замена наибольшего достаточно малым числом

ReadJust ( i , tree );//переупорядочивание вдоль пути от i к 1

}

и присваивания x [1]= tree [ tree [1]].

Приведем окончательный текст программы

#include <iostream.h>

#include <conio.h>

void Initialize (int n, int size, int small, int *x, int *tree)

{ int i,j,k;

for (i=1; i<=n; i++) tree [size+i-1]=x[i];

for (i=size+n; i<=2*size-1; i++) tree[i]=small;

for (j=size; j<=2*size-1; j+=2)

if (tree[j]>=tree[j+1]) tree[j/2]=j; else tree[j/2]=j+1;

k=size/2;

while (k>0)

{

for (j=k; j<=2*k-1; j+=2)

if (tree[tree[j]]>=tree[tree[j+1]]) tree[j/2]=tree[j];

else tree[j/2]=tree[j+1];

k/=2;

}

}

void ReadJust(int i, int *tree)

{

int j;

if (i%2==0) tree[i/2]=i+1;

else tree[i/2]=i-1;

i=i/2;

while(i>1)

{

if (i%2==0) j=i+1;

else j=i-1;

if (tree[tree[i]]>tree[tree[j]])

tree[i/2]= tree[i];

else tree[i/2]=tree[j];

i=i/2;

}

}

void Tourtament (int n, int *x)

{ int i, k, size, small, tree[1023];

size=1; small=-32768;

while (size<n) size*=2;

Initialize (n, size, small, x, tree);

for (k=n; k>1; k--)

{ i=tree[1];

x[k]=tree[i];

tree[i]=small;

ReadJust (i, tree);

} x[1]=tree[tree[1]];

}

void main ()

{ int x[]={0, 45, 23,12, 34, 1, 87, 42, 11, 5, 36, 12, 3, 5, 8, 99, 2 }, n=16;

clrscr ();

cout<<"До сортировки:"<<endl;

for (int i=1; i<=n; i++) cout << x[i] << " ";

Tourtament (n, x);

cout<<endl<<" После сортировки :"<<endl;

for (i=1; i<=n; i++) cout << x[i] << " ";

getch ();

}

Результаты работы программы

До сортировки:

45 23 12 34 1 87 42 11 5 36 12 3 5 8 99 2

После сортировки:

1 2 3 5 5 8 11 12 12 23 34 36 42 45 87 99

up