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

Упорядоченные деревья. Поиск заданного значения.

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

Функция Findосуществляет поиск узла со значением равным параметру Х. ПараметрR–указатель на корень дерева, в котором осуществляется поиск. Возвращаемый результат:True– узел со значением Х найден,False– не найден.

Листинг функции поиска в бинарном дереве

FunctionFind(R:PTree;X:integer):boolean;

begin

ifR=nilthenResult:=false{Дошли до тупика, искать больше негде.}

else // Указатель на дерево не пуст

ifR^.inf=Xthen// Проверяем содержимое на равенство

Result:=True// Узел найден

else

if n < R^.inf then

find:=find(R^.left,X) // Продолжаем поиск в левом поддереве

else

find:=find(R^.right,X); // Продолжаем поиск в правом поддереве

end;

Функцию Findможно записать иначе, изменив тип возвращаемого результата с логического типа на указатель узла бинарного дерева. В этом случае при успешном поиске получаем адрес найденного элемента, при неудаче – пустой указательnil.

Удаление бинарного дерева.

После окончания работы с такой динамической структурой как бинарное дерево необходимо высвободить память, удалив все его узлы. Для удаления узлов бинарного дерева воспользуемся процедурой обхода cнизу вверх(PosOrder). Только такой порядок обхода гарантирует корректное удаление всех узлов (При удалении необходимо освобождать сначала самые крайние дочерние узлы, постепенно переходя на вышележащие родительские уровни. Последним должен быть удален корень дерева). Решает эту задачу процедураDeleteTree. В рекурсивную процедуру передается как параметр-переменная адрес корня дерева. После выхода из процедуры фактический параметр, будет продолжать хранить адрес бывшего корня дерева, но обращение по нему вызовет ошибку. Поэтому, после удаления дерева указателю на корень желательно присвоить значениеnil, т.е. провести его повторную инициализацию.

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

procedure DeleteTree (var Root: ptelem);

begin

if r <> nil then

begin

DeleteTree (r^.left);

DeleteTree (r^.right);

dispose(r);

end;

end;

Удаление узла из упорядоченного дерева

Рассмотрим задачу, обратную включению, - удаление заданного узла из упорядоченного дерева. После операции удаления узла дерево должно остаться упорядоченным. Удаление является простым в случае, когда удаляемый узел – лист. Тогда лист просто удаляется. Если удаляемый узел имеет только одного сына, то удаляемый узел заменяется узлом-сыном. Трудность возникает при удалении узла с двумя сыновьями, т.к. невозможно указать ссылкой два направления. В этом случае удаляемый узел нужно заменить либо на самый правый элемент его левого поддерева, либо на самый левый элемент его правого поддерева. Ясно, что такие элементы не могут иметь более одного потомка.

Алгоритм удаления узла с ключом хиз упорядоченного дерева реализован процедуройDelete(), приведенной далее.

Процедура обрабатывает три случая:

  • В дереве нет узла с ключом х.

  • Узел с ключом химеет не более одного сына.

  • Узел с ключом химеет двух сыновей.

Параметры процедуры: x– значение удаляемого узла,Tree– указатель на корень дерева,moving– флаг удаления (moving=True– узел найден и удален, иначе -False)

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

Procedure Delete(x:integer; var Tree:PTree; var moving: boolean);

Varq :PTree;

ProcedureDel(var R:PTree);

begin

If R^.Right <> nil then Del(R^.Right)

else begin

q^.inf:=R^.inf;

q:=R; R;=R^.left;

end;

end;

begin

If Tree = nil then moving:=false // узел для удаления не найден

else

If x< Tree^.inf then Delete(x,Tree^.left,moving)

else

If x> Tree^.inf then Delete(x,Tree^.right,moving)

else

begin // удаление узла

Moving:=true; q:=Tree;

If q^.right=nil then Tree:=q^.left

else

If q^.left= nil then Tree:=q^.right

else

Del(q^.left);

Dispose(q);

end

end;

Вспомогательная рекурсивная процедура Del() вызывается только в случае, когда удаляемый узел имеет двух сыновей. Она “спускается” вдоль самой правой ветви левого поддерева удаляемого узлаq^, а затем заменяет ключ вq^ соответствующим значением самого правого узлаr^ этого левого поддерева. После чегоr^ удаляется. Параметр-переменнаяmovingпередает сведения о том, был ли удален требуемый узел.True– узел найден и удален,false - в противном случае.