Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
САОД Part 1.DOC
Скачиваний:
41
Добавлен:
02.11.2018
Размер:
1.68 Mб
Скачать
  1. Реализация операций над деревом поиска

Поиск элемента с ключом Key может быть выполнен с помощью итерации, так как поиск идет по единственному пути от корня к искомому узлу:

function tSearchTree.Addr(Key: tValue): pItem; // адрес элемента с ключом Key

var

Item: pItem;

begin

if Empty

then Addr:= nil

else begin

Item:= fRoot;

while (Item<>nil) and (Item^.Value<>Key) do

if Key<Item^.Value

then Item:= Item^.Left // спуск по левой ветви

else Item:= Item^.Right; // спуск по правой ветви

Addr:= Item;

end;

end; // function tSearchTree.Addr

Метод, реализующий поиск по дереву с включением:

function tSearchTree.Search(Key: tValue):pItem;

// Поиск элемента с заданным ключом Key с включением

procedure IncKey(var Item: pItem); // рекурсивная процедура поиска

begin

if Item=nil

then begin // элемента с ключом Key нет: включение его в качестве листа

Item:= New(pItem); Item^.Value := Key;

Item^.Left:= nil; Item^.Right:=nil;

Result:= Item; Inc(fSize);

end

else

if Key<Item^.Value then IncKey(Item^.Left) // поиск слева

else

if Key>Item^.Value then IncKey(Item^.Right) // поиск справа

else Result:= Item; // элемент найден

end; // procedure IncKey

begin

IncKey(fRoot);

end; // function tSearchTree.Search

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

ситуация 1: элемента с ключом Key нет в дереве, в этом случае дерево остается неизменным;

ситуация 2: элемент с ключом Key имеет не более одного потомка – после исключения ближайший потомок поднимается на его место;

ситуация 3: элемент с ключом Key имеет двух потомков, в этом случае исключаемый элемент нужно заменить самым правым элементом его левого поддерева, имеющим не более одного потомка. Этому условию соответствует элемент, предшествующий исключаемому в обходе слева направо. После исключения узла с двумя потомками дерево останется деревом поиска и в том случае, если заменить исключаемый элемент самым левым элементом его правого поддерева, имеющим не более одного потомка. Этому условию соответствует элемент, следующий за исключаемым в обходе слева направо.

Ниже приведено исходное дерево поиска (а). Дерево ) получается из дерева (а) после исключения элемента 15 и замены его элементом 11 – самым правым элементом левого поддерева узла 15 (в процедуре обхода слева направо он предшествует узлу 15). Дерево (в) получается из дерева (а) после исключения элемента 15 и замены его элементом 18 – самым левым элементом правого поддерева узла 15 (в процедуре обхода следует за узлом 15).

(а) (б) (в)

procedure tSearchTree.Delete(Key: tValue);

// Поиск элемента с заданным ключом Key с исключением

procedure DelKey(var Item: pItem); // основная рекурсивная процедура

var

DelItem: pItem; // указатель на исключаемый элемент

procedure Del(var Addr: pItem);

// Вспомогательная рекурсивная процедура. Возвращает адрес самого

// правого элемента левого поддерева удаляемого узла DelItem

begin

if Addr^.Right<>nil

then Del(Addr^.Right) // поиск правого элемента

else begin

// Найден самый правый элемент левого поддерева DelItem

DelItem^.Value:= Addr^.Value; DelItem:= Addr; Addr:= Addr^.Left;

end;

end; //procedure Del

begin

if Item=nil

then WriteLn('Узел с ключом',Key,'не найден.') // ситуация 1

else

if Key<Item^.Value

then DelKey(Item^.Left) // поиск слева

else

if Key>Item^.Value

then DelKey(Item^.Right) // поиск справа

else begin

// элемент найден, исключение Item^

DelItem:= Item;

if DelItem^.Right=nil

then Item:= DelItem^.Left // ситуация 2

else

if DelItem^.Left=nil

then Item:= DelItem^.Right // ситуация 2

else Del(DelItem^.Left); // ситуация 3 – поиск предшественника

Dispose(DelItem); Dec(fSize); // удаление перемещенного элемента

end; // конец исключения Item^

end; // procedure DelKey

begin

DelKey(fRoot);

end; // procedure tSearchTree.Delete

В методе tSearchTree.Delete используется основная рекурсивная процедура DelKey, которая собственно и выполняет поиск в дереве с удалением. Вспомогательная рекурсивная процедура Del начинает работать только в ситуации 3. Она «спускается» вдоль правой ветви левого поддерева элемента с указателем DelItem, который нужно исключить, и заменяет поле Value элемента DelItem^ на соответствующее значение из самого правого элемента Addr^ левого поддерева, после чего от элемента Addr^ можно освободиться.

Построение дерева поиска заключается в считывании из входного потока (в данной реализации из текстового файла) элементов с заданными ключами и включении их в дерево поиска с использованием операции поиска по дереву с включением Search(Key).

procedure tSearchTree.Build(var f: Text); // построение дерева поиска

var

Key : tValue;

begin

while not Eof(f) do begin

Read(f, Key); if Eoln(f) then ReadLn(f);

Search(Key); // функция Search вызывается как процедура

end;

end; //procedure tSearchTree.Build