Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
attachments_03-09-2012_10-20-12 / Бинарные деревья - дерево бинарного поиска.doc
Скачиваний:
71
Добавлен:
21.05.2015
Размер:
121.86 Кб
Скачать

Обход бинарного дерева.

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

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

Существуют три порядка, использующие обход в глубину:

  1. Сверху вниз(PreOrder):

  • обработать корень;

  • обходлевого поддерева;

  • обход правого поддерева;

  1. Слева направо(InOrder):

  • обходлевого поддерева;

  • обработать корень;

  • обходправого поддерева;

  1. Снизу вверх(PosOrder):

  • обходлевого поддерева;

  • обходправого поддерева;

  • обработать корень.

Для дерева на рис.1 три способа обхода дают следующий результат:

Обход

Порядок посещения узлов

PreOrder

100

70

50

10

55

60

58

65

90

150

200

170

210

InOrder

10

50

55

58

60

65

70

90

100

150

170

200

210

PosOrder

10

58

65

60

55

50

90

70

170

210

200

150

100

Эти три метода легко представить в виде рекурсивных процедур, листинг которых представлен ниже. Во всех процедурах в качестве обработки корня используется вывод значения информационного поля на экран. В качестве параметра Tree:PTreeв процедуры передается адрес корня бинарного дерева.

Листинг процедур обхода бинарного дерева.

Procedure PrintTree(Tree: PTree); // PreOrder

begin

if Tree<>nilthen begin //если дерево не пустое, то

Writeln(‘Value = ‘,Tree^.inf); // обработать узел

PrintTree(Tree^.Left); //обходлевого поддерева

PrintTree(Tree^.Right); //обходправого поддерева

end;

end;

Procedure PrintTree(Tree: PTree); // InOrder

begin

if Tree<>nil then begin // если дерево не пустое, то

PrintTree(Tree^.Left); //обходлевого поддерева

Writeln(‘Value = ‘,Tree^.inf); // обработать узел

PrintTree(Tree^.Right); //обходправого поддерева

end;

end;

Procedure PrintTree(Tree: PTree); // PosOrder

begin

if Tree<>nil then begin // если дерево не пустое, то

PrintTree(Tree^.Left); //обходлевого поддерева

PrintTree(Tree^.Right); //обходправого поддерева

Writeln(‘Value = ‘,Tree^.inf); // обработать узел

end;

end;

Ссылка Treeпередается как параметр-значение, следовательно, является локальной переменной процедуры, получающей копию фактического параметра. При ее изменении фактический параметр не измениться (т.к. процедура работает с его локальной копией). Это означает, что при передаче в качестве фактического параметра адреса корня дерева, хранящая его переменная останется неизменной.

Упорядоченные деревья. Включение нового узла, поиск по дереву с включением

Упорядоченнымназывается дерево, в котором для каждого узлаNзначение левого дочернего узла меньше, чем значение вN, а значение правого дочернего узла больше значения вN. Если в дереве могут содержаться одинаковые значения, то программист должен самостоятельно определить, влево или вправо помещать значение, равное значению в родительском узле (строгое неравенство заменить на нестрогое).

Построение упорядоченного дерева начинается с корня. Первое входящее значение помещается в корень дерева. Для последующих значений производиться сравнение со значением в очередном узле, начиная с корня. Если оно меньше (или равно) значению в узле, то переходим в левое поддерево, иначе – в правое. Эти переходы и сравнения продолжаются до тех пор, пока мы не придем к ссылке, которая равна nil. Тогда создается новый узел, заполняются его поля: информационное - новым значением, ссылки на левое и правое поддеревья пустым значениеnil. Адрес нового узла передается в одно из ссылочных полей родительского узла. Для этого необходимо воспользоваться параметром-переменной. Этот алгоритм реализован в виде рекурсивной процедурыInsert.

Рис.2 Добавление нового узла в упорядоченное дерево.

Листинг процедуры добавления нового узла в упорядоченное дерево.

{Параметры процедуры: Tree– указатель на корень дерева,NewValue– значение для добавляемого узла.}

Procedure Insert(var Tree:PTree; NewValue:integer);

varTemp:PTree;

begin

if Tree = nil then begin

new(Tree); // создание нового узла, в том числе и корневого

Tree^.inf:=NewValue; Tree^.Left:=nil; Tree^.Right:=nil; // заполнение полей

end

else

if NewValue <=Tree^.inf then

Insert(Tree^.left,NewValue)

{переход к левому поддереву}

else

Insert(Tree^.Right,NewValue)

{переход к правому поддереву}

end;

Следует отметить, что в процедуре InsetrпараметрTreeпередается как параметр-переменная, а не как параметр-значение в процедуреPrintTree. Это очень важно, так как в случае включения нового узла параметру-переменнойTreeприсваивается адрес нового узла и через нее передает в родительский узел ссылкы (адрес) на включенный узел, изменяя старое значение равноеnil.Само по себе создание бинарного дерева тривиально. В простейшем случае корневой узел бинарного дерева определяет все бинарное дерево. В программе необходимо описать указатель на корень дерева (например, var Root:PTree;). В начале программы необходимо провести инициализацию бинарного дерева – указателю на корень присвоить пустое значение (Root:=nil;). Бинарного дерева не существует, поэтому это пустое значение служит начальным значением бинарного дерева. Добавление новых элементов в дерево будем осуществлять процедурой Insert. Например, добавление числа Х в бинарное дерево будет выглядеть так: Insert(Root,X). Вывод на экран содержимого дерева можно записать процедурой PrintTree(Root).

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

Procedure PrintTree1(Tree: PTree); // InOrder

begin

if Tree<>nil then begin // если дерево не пустое, то

PrintTree1(Tree^.Right); //обходправого поддерева

Writeln(‘Value = ‘,Tree^.inf); // обработать узел

PrintTree1(Tree^.Left); // обход левого поддерева

end;

end;