Бинарные деревья поиска

 

Бинарным деревом поиска называется бинарное дерево из элементов, в котором ключ элемента в каждой вершине больше ключей всех элементов левого поддерева и меньше ключей элементов правого поддерева. Ниже приведен пример бинарного дерева поиска с числовыми значениями ключей.

 

 


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

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

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

Наряду с поиском деревья поиска обеспечивают сортировку элементов. Действительно, обход дерева в порядке слева направо дает перечисление элементов по возрастанию ключей.

Включение нового элемента в дерево поиска выполняется следующим образом. Сначала производится поиск элемента с ключом, равным ключу нового элемента. После прихода в лист элемент войдет в новую вершину дерева, которая будет левым или правым сыном найденного листа в зависимости от значения ключа элемента.

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

1. Удаляемый элемент находится в листе дерева. В этом случае удаляется соответствующая ссылка из отцовской вершины.

2. Удаляемый элемент находится в вершине с одним сыном. На место вершины с данным элементом помещается ее единственный сын со всеми своими потомками, то есть подтягивается все поддерево по имеющейся ветви.

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

Например, удаление элемента с ключом 20 из дерева поиска, приведенного выше, даст следующий результат

 

 


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

Program PoiskVkl;

{ поиск с включением на бинарном дереве }

Uses Crt;

Type

ref= ^word;

word=record

Key: string;

Count: integer;

Left, Right: ref

end;

Var

Root: ref;

Rab: string;

B: boolean;

Procedure Search(X: string; var P: ref);

Begin

if P=Nil then { слова нет - включить ! }

begin

New(P);

with P^ do

begin

Key:=X;

Count:=1; Left:=Nil; Right:=Nil

end

end

else

if X<P^.Key then Search(X, P^.Left)

else

if X>P^.Key then Search(X, P^.Right)

else { нашли слово }

P^.Count:=P^.Count+1

End;

Procedure Delete(X: string; var P: ref);

{ память освобождается, описатель var - обязателен }

Var

Q: ref;

Procedure Del(var R: ref); { сначала R=Q^.Left }

{ замещение Q^ самым правым элементом левого поддерева }

Begin

if R^.Right<>Nil then Del(R^.Right)

else

begin { R-самая правая вершина левого поддерева }

Q^.key:=R^.Key;

Q^.Count:=R^.Count;

Q:=R;

R:=R^.Left; { подтянули левое поддерево }

Dispose(Q)

end

End;

Begin

if P=Nil then

WriteLn('Слова нет в дереве !')

else

if X<P^.Key then Delete(X, P^.Left)

else

if X>P^.Key then Delete(X, P^.Right)

else { X=P^.Key - нашли слово }

if P^.Count>1 then P^.Count:=P^.Count-1

else

begin { полное удаление слова }

Q:=P; { Q – указатель на удаляемую вершину }

if Q^.Right=Nil then

begin

P:=Q^.Left; { подтянули левое поддерево }

Dispose(Q)

{ работает, благодаря рекурсии: меняя P, меняется }

{ P^.Left или P^.Right у отцовской вершины }

end

else if Q^.Left=Nil then

begin

P:=Q^.Right; { подтянули правое поддерево }

Dispose(Q)

end

else Del(Q^.Left); { замена }

end

End;

Procedure PrintTree(W: ref; L: integer);

{ W-корень, L-число точек, показывающее уровень дерева }

Var

I: integer;

Begin

if W<>Nil then

with W^ do

begin

PrintTree(Left, L+1);

For I:=1 to L do

Write('.');

WriteLn(Key, ' ', Count);

PrintTree(Right, L+1)

end

End;

Begin

ClrScr;

Rab:=' ';

Root:=Nil;

B:=True;

While B do

begin

Write('Укажите слово для ввода (к-признак конца) ');

Readln(Rab);

if Rab<>'к' then

begin

Search(Rab, Root);

PrintTree(Root, 0)

end

else B:=False

end;

B:=True;

While B do

begin

Write('Укажите слово для удаления (к-признак конца) ');

Readln(Rab);

if Rab<>'к' then

begin

Delete(Rab, Root);

PrintTree(Root, 0)

end

else B:=False

end;

End.

 








Дата добавления: 2015-08-21; просмотров: 1160;


Поиск по сайту:

При помощи поиска вы сможете найти нужную вам информацию.

Поделитесь с друзьями:

Если вам перенёс пользу информационный материал, или помог в учебе – поделитесь этим сайтом с друзьями и знакомыми.
helpiks.org - Хелпикс.Орг - 2014-2024 год. Материал сайта представляется для ознакомительного и учебного использования. | Поддержка
Генерация страницы за: 0.021 сек.