Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие часть 1.doc
Скачиваний:
63
Добавлен:
24.09.2019
Размер:
6.98 Mб
Скачать

3.6.3. Пример — построение дерева турнира

В качестве первого примера построения бинарного дерева представлена функция для построения так называемого «дерева турнира» (функция называется contest). Данная функция является рекурсивной и использует базовые функции для работы с бинарным деревом. При этом педполагается, что реализация бинарного дерева может быть выполнена любым способом и находится в файлах bintree.h и bintree.cpp.

Сначала поясним, что представляет собой дерево турнира [Сэнджвик]. Это бинарное дерево, в котором вся полезная информация содержится в листьях, а каждый внутренний узел — это копия наибольшего из его сыновей. Следовательно, корень такого дерева — копия наибольшего из значений листьев. Поэтому дерево турнира может быть использовано, например, для определения максимального значения в последовательности (при этом используется термин «разыграть турнир», очевидно, по аналогии с турниром по теннису, где после каждой игры проигравший выбывает). К сожалению, такой способ определения максимального элемента не эффективнее, чем обычный способ с использованием цикла. Это и понятно — ведь для того, чтобы найти наибольший из n элементов, нужно убедиться, что все остальные (n-1) элементов его меньше, для чего требуется выполнить (n-1) сравнений.

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

Листинг 3.3. Построение дерева турнира

#include <iostream.h>

#include “bintree.h” // подключили определение бинарного дерева

// рекурсивная функция построения дерева турнира

// low и high – индексы начала и конца части массива,

// для которой разыгрывается турнир

bt contest(int *c, int low, int high)

{ bt l,r; int m;

if (low==high)// терминальная ветвь – остался один элемент

return consbt(c[low],NULL,NULL);// листья - элементы массива

m=(low+high)/2; // находим середину части массива

// затем разыгрываем турнир для левой и правой половин

l=contest(c,low,m); r=contest(c,m+1,high);

// внутренние узлы - копия наибольшего из двух детей

if (root(l)>root(r))return consbt(root(l),l,r);

else return consbt(root(r),l,r);

}

// В качестве примера разыграем турнир для массива из 10 элементов

int main()

{ int c[10]={0,1,2,3,4,5,6,7,8,9};

out(contest(c,0,9)); return 0;

}

На рис. 3.11 изображено дерево турнира для массива из 10 элементов, который используется в программе в качестве примера. Сама программа выводит дерево в левом скобочном представлении, хотя написать функцию, которая выведет дерево в виде двухмерного рисунка — задача чисто техническая.

Рис.3.11. Дерево турнира, построенное программой из листинга 3.10.

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