Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Тема 15. Бинарные деревья

Дерево — это динамическая структура данных, состоящая из элементов, называемых узлами, и отношений (родительский–дочерний), образующих иерархическую структуру узлов. Исходящие узлы называются предками, входящие — потомками. Начальный узел, то есть узел не имеющий родителя, называется корнем дерева. Каждый узел, кроме корня, имеет ровно одного предка. Узлы могут являться величинами любого простого или структурированного типа, за исключением файлового. Узел, не имеющий поддеревьев, называется листом. Высота дерева определяется количеством уровней, на которых располагаются его узлы.

Бинарное дерево это дерево, каждый узел которого имеет не более двух потомков.

 
 

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

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

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

Для бинарных деревьев определены операции:

- включения узла в дерево;

- поиска по дереву;

- обхода дерева;

- удаления узла.

 

Рекурсивную функцию обхода всех узлов дерева в общем виде можно описать так:

Тип ОБХОД (дерево){

ОБХОД (левое поддерево)

посещение корня

ОБХОД (правое поддерево) }

При обходе дерева узлы не удаляются.

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

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

· обход в прямом (префиксном) порядке (обход сверху- вниз), то есть посещаем сначала корень, потом поддеревья,

· обход в обратном (постфиксном) порядке (обход снизу вверх), то есть посещаем сначала поддеревья, а потом корень.

Интересно проследить результаты этих трех обходов на примере записи формул в виде дерева.

Например, формула

(a+b/c)*(d-e*f)

может быть представлена так

 
 

 

 


Прямой обход дает обычную инфиксную запись числа (только без скобок).

Префиксный обход дает префиксную запись числа +a/bc-d*ef

Постфиксный обход дает польскую инверсную запись числа (ПОЛИЗ) abc/+def*-*

 

Таким образом, деревья поиска можно применять для сортировки значений.

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

Программа формирует дерево из массива целых чисел и выводит его на экран.

#include <iostream.h>

struct Node

{

int d;

Node *left;

Node *right;

};

 

Node * first(int d);

Node * search_insert(Node *root, int d);

void print_tree(Node *root, int l);

 

// ---------------------------------

int main()

{

int b[] = {10, 25, 20, 6, 21, 8, 1, 30};

Node *root = first(b[0]);

for (int i = 1; i<8; i++) search_insert(root, b[i]);

print_tree(root, 0);

return 0;

}

//------------------------------------

//Формирование первого элемента дерева

Node * first (int d)

{

Node *v=new Node;

pv->d = d;

pv->left = 0;

pv->right = 0;

return pv;

}

//-----------------------------------------------

// Поиск с включением

Node * search_insert(Node *root, int d)

{

Node *pv = root,*prev;

bool found = false;

while (pv &&!found)

{

prev = pv;

if (d == pv->d) found = true;

else if (d < pv->d) pv = pv->left;

else pv = pv->right;

}

if (found) return pv;

// Создание нового узла

Node *pnew = new Node;

pnew->d= d;

pnew->left = 0;

pnew->right = 0;

if (d < prev->d)

//Присоединение к левому поддереву предка

prev->left= pnew;

else

//Присоединение к правому поддереву предка

prev->right = pnew;

return pnew;

}

 

//---------------------------------------------

// Обход дерева

void print_tree(Node *p, int level)

{

if (p)

{

print_tree(p->left, level +1); // вывод левого поддерева

for (int i = 0; i<level; i++) cout <<" ";

cout<< p->d<<endl; // Вывод корня поддерева

print_tree(p->right, level + 1);// вывод правого поддерева

}

}

 

Текущий указатель для поиска по дереву обозначен рv, указатель на предка рv обозначен ргеv, переменная рnew используется для выделения памяти под включаемый в дерево узел. Рекурсии удалось избежать, сохранив всего одну перемен­ную (ргеv) и повторив при включении операторы, определяющие, к какому поддереву присоединяется новый узел.

 

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

Рассмотрим подробнее функцию обхода дерева. Вторым параметром в нее переда­ется целая переменная, определяющая, на каком уровне находится узел. Корень находится на уровне 0. Дерево печатается по горизонтали так, что корень находится слева (посмотрите на результат работы программы, наклонив голову вле­во, и сравните с рисунком дерева, приведенным выше). Перед значением узла для имитации структуры дерева выводится количество пробелов, пропорциональное уровню узла. Если закомментировать цикл печати пробелов, отсортированный по возрастанию массив будет выведен в столбик. Заметьте, что функция обхода дерева длиной всего в несколько строк может напечатать дерево любого размера — важно только следить, чтобы рекурсивные вызовы не переполнили стек.

Удаление узла из дерева представляет собой не такую простую задачу, поскольку удаляемый узел может быть корневым, содержать две, одну или ни одной ссылки на поддеревья. Для узлов, содержащих меньше двух ссылок, удаление тривиаль­но. Чтобы сохранить упорядоченность дерева при удалении узла с двумя ссылками, его заменяют на узел с самым близким к нему ключом. Это может быть самый левый узел его правого поддерева или самый правый узел левого поддерева (например, чтобы удалить из дерева на рисунке узел с ключом 25, его нужно заменить на 21 или 30, узел 10 заменяется на 20 или 8, и т. д.). Реализация функции удаления из дерева оставлена для самостоятельной работы.

 

<== предыдущая лекция | следующая лекция ==>
Нахождении базиса, в котором матрица данного оператора диагональная | План лекции. Лекция 17. Международное движение капитала
Поделиться с друзьями:


Дата добавления: 2014-01-04; Просмотров: 606; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.023 сек.