Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ДЕРЕВЬЯ.doc
Скачиваний:
23
Добавлен:
13.02.2015
Размер:
241.15 Кб
Скачать

СОДЕРЖАНИЕ: ДЕРЕВЬЯ

1 Основные понятия и определения . . . . . . . . . . . . . . . . . . . . . . . .

4

2 Двоичные деревья . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7

3 Основные операции с двоичными деревьями . . . . . . . . . . . . . . .

9

3.1 Обход дерева . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9

3.2 Обработка узлов дерева . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

4 Дерево поиска ( сортировки ) . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19

4.1 Построение дерева поиска . . . . . . . . . . . . . . . . . . . . . . . . . . .

20

4.2 Поиск и включение для дерева сортировки . . . . . . . . . . . . .

24

4.3 Исключение из дерева поиска . . . . . . . . . . . . . . . . . . . . . . . .

27

5 Сбалансированные деревья . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

30

ЛИТЕРАТУРА . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

  1. ОСНОВНЫЕ ПОНЯТИЯ И ОПРЕДЕЛЕНИЯ

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

Деревья имеют ярко выраженную рекурсивную структуру. Рекурсивные алгоритмы при работе с деревьями получаются более компактными, элегантными, они легче для понимания, чем итеративные алгоритмы.

Деревья часто встречаются в повседневной жизни и хорошо известны по генеалогическим деревьям (рисунки 1 и 2) и структурам с иерархической организацией.

Определим дерево как непустое множество T элементов – узлов ( или вершин ) таких, что

а) имеется единственный особый узел, называемый корнем данного дерева;

б) остальные узлы содержатся в m >= 0 попарно не пересекающихся множествах T1 , ... , Tm , каждое из которых в свою очередь является деревом.

Это определение является рекурсивным, т.е. дерево определяется в терминах самих же деревьев.

Можно дать и нерекурсивное определение дерева, но рекурсивное определение более подходящее, т.к. рекурсивность является естественной характеристикой структур типа дерево.

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

Существует несколько способов изображения структуры дерева. Структура, представленная в виде графа (рисунок 3) и явно отражающая разветвления, привела к появлению термина “дерево”. При этом принято корень дерева изображать как верхнюю вершину.

То есть дерево можно определить как граф, в котором

а) имеется одна особая вершина, называемая корнем, в которую не заходит ни одно ребро;

б) во все остальные вершины заходит ровно одно ребро, а исходит сколько угодно ребер.

По аналогии с деревьями ребра называют ветвями, а вершины на концах ветвей – листьями.

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

Итак, терминология, используемая в связи с деревьями, включает следующие понятия:

Узел или вершина – каждый элемент дерева.

Поддерево называют потомком по отношению к своей вершине – предку.

Корень – особая вершина дерева, не имеющая предка.

Каждый узел, кроме корня, имеет единственного предка.

Вершина связана с каждым из своих поддеревьев ветвью.

Узлы, не имеющие поддеревьев ( потомков ), называются листьями или терминальными вершинами.

Узлы, не являющиеся терминальными, называются внутренними.

Число непосредственных потомков внутреннего узла называется его степенью.

Максимальная степень всех узлов есть степень дерева.

Вершина (например, D на рисунке 3), находящаяся непосредственно ниже другой вершины (B на рисунке 3), называется непосредственным ее потомком; если непосредственный предок находится на уровне h, то его непосредственный потомок лежит на уровне h + 1 .

Корень дерева находится на нулевом уровне.

Максимальный уровень какой-либо из вершин дерева называется его глубиной или высотой. То есть глубина дерева определяется числом вершин в самом длинном из путей от корня дерева до листьев.

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

Упорядоченное дерево – это дерево, у которого ветви, исходящие из каждой вершины, упорядочены.

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

2. Двоичные деревья

Особенно важную роль играют упорядоченные деревья второй степени. Их называют двоичными или бинарными деревьями.

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

Заметим, что двоичное дерево не является частным случаем дерева, хотя эти два понятия связаны между собой. Основные отличия между ними:

1) Дерево никогда не бывает пустым, т.е. имеет, по меньшей мере, один узел, а двоичное дерево может быть пустым.

2) Двоичное дерево - упорядоченное дерево, т.е. делается различие между левым и правым поддеревом, даже в том случае, когда узел имеет лишь одного потомка. В графическом изображении дерева (рисунок 4) “наклон” ветвей важен.

Реализация таких рекурсивных структур, как двоичные деревья, приводит к использованию ссылок (указателей).

Ссылки на пустые деревья будут обозначаться nil.

Из определения двоичных деревьев следует естественный способ их описания ( и представления в компьютере ) : для этого достаточно иметь две связи L и R в каждом узле и переменную связи T, которая является указателем на это дерево. Если дерево пусто, то T = nil ; в противном случае T - адрес корня этого дерева, а L и R - указатели соответственно на левое и правое поддеревья этого корня.

На языке Паскаль узлы бинарного дерева описываются как записи с одним или несколькими информационными полями и двумя полями – указателями. Если Elem - тип информационной части узлов дерева, то компоненты дерева ( узел и ссылка на узел ) имеют такие типы:

type Tree = ^Node; { указатель на узел }

Node = record { узел дерева }

Inf : Elem;

L, R : Tree

end;

Таким образом, дерево на рисунке 4 б) можно представить так, как на рисунке 5.

Далее будем иметь дело только с двоичными деревьями, поэтому термин “дерево” будет означать двоичное дерево.

3. Основные операции с двоичными деревьями

3.1. Обход дерева

Наиболее распространенная задача обработки древовидных структур – выполнение некоторой определенной операции над каждым элементом дерева. При этом происходит “посещение” всех вершин, т.е. обход дерева. При обходе каждый узел проходится, по меньшей мере, один раз, а, вообще говоря, три раза. Полное прохождение дерева дает линейную расстановку узлов. Если, обходя дерево, обрабатывать вершины при первой встрече, то ( см. рис. 4 б) ) получим последовательность A, B, D, E, C, F ; если при второй встрече, то получим D, B, E, A, C, F ; если при третьей встрече, то получим D, E, B, F, C, A.

Эти три способа обхода называются соответственно

– обходом сверху вниз (в прямом порядке, префиксным обходом, preorder);

– обходом слева направо (в обратном порядке, инфиксным обходом, inorder);

– обходом снизу вверх (в концевом порядке, постфиксным обходом, postorder или endorder).

Способы прохождения деревьев определяются рекурсивно. Если дерево пусто, то никаких действий не выполняется, в противном случае обход выполняется в три этапа

Префиксный обход

Инфиксный обход

Обработать узел

Пройти левое поддерево

Пройти левое поддерево

Обработать узел

Пройти правое поддерево

Пройти правое поддерево

Постфиксный обход

Пройти левое поддерево

Пройти правое поддерево

Обработать узел

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

Все три метода легко представляются как рекурсивные процедуры.

Пример 3.1. Префиксный обход дерева :

procedure PreOrder(T : Tree);

begin

if T <> nil then

begin

{ операция обработки узла дерева , например, writeln( T^.inf );}

PreOrder (T^.L);

PreOrder (T^.R)

end

end; { PreOrder }

Пример 3.2. Инфиксный обход дерева :

procedure InOrder(T : Tree);

begin

if T <> nil then

begin

InOrder (T^.L);

{ операция обработки узла дерева , например, writeln( T^.inf );}

InOrder (T^.R)

end

end; { InOrder }

Пример 3.3. Постфиксный обход дерева :

procedure PostOrder(T : Tree);

begin

if T <> nil then

begin

PostOrder (T^.L);

PostOrder (T^.R)

{ операция обработки узла дерева , например, writeln( T^.inf );}

end

end; { PostOrder }

Замечание. Ссылка T передается как параметр - значение, т.е. в процедуре используется ее локальная копия.

При реализации нерекурсивных процедур обхода дерева обычно используют вспомогательный стек и операции работы с ним:

– очистить стек (создать пустой стек);

– проверить, является ли стек пустым;

– добавить в стек элемент;

– извлечь элемент из стека.

В стеке запоминаются ссылки на вершины (поддеревья), обработка которых временно откладывается.

Пример 3.4. Описать нерекурсивную процедуру префиксного обхода дерева.

Описание вспомогательного стека :

type Stack = ^Rec;

Rec = record