- •Оглавление
- •Бинарные деревья
- •Основные понятия и определения.
- •Основные операции с бинарными деревьями Узел бинарного дерева
- •Обход бинарного дерева.
- •Упорядоченные деревья. Включение нового узла, поиск по дереву с включением
- •Упорядоченные деревья. Поиск заданного значения.
- •Удаление бинарного дерева.
- •Удаление узла из упорядоченного дерева
- •Пример использования упорядоченного бинарного дерева для частотного анализа данных
Упорядоченные деревья. Поиск заданного значения.
Упорядоченное дерево можно эффективно применять для поиска. Действительно, поиск значения х осуществляется перемещением по дереву линейно, выбирая на каждом этапе (в каждом узле) направление дальнейшего движения – налево или направо, в зависимости от результата сравнения значения Х со значением в узле. Окончание поиска – или найденное значение или пустой указатель (искать уже негде) При таком алгоритме нет надобности перебирать все значения подряд, поэтому число сравнений здесь минимально. Поиск в бинарном дереве сравним по эффективности с бинарным поиском в упорядоченном массиве.
Функция 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 - в противном случае.