7.3. Основные операции с бинарным деревом поиска

При использовании организации списков в виде двоичного дерева целесообразно создать класс (Листинг 7.5), реализующий следующие методы:

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

  • вставка информации с новым значением ключа не изменяя свойств дерева поиска;

  • формирование сбалансированного дерева поиска;

  • поиск заданного ключа;

  • поиск минимального (максимального) ключа;

  • удаление информации с заданным ключом;

  • удаление дерева.

Type Ttree=^Tre Листинг 7.5

Tre=Record

Inf:tInf;

A1,A2:Ptree;

End;

Tree=Class(tobject)

proot,p,q,v,w:Ttree;//указатель на корень и рабочие

Destructor Free;

Procedure Tree.Add(Inf:TInf);

Procedure Wrt1;

Function poisk(k:Tkey):TInf;

Function Mink:TInf;

Procedure Delk(k:Tkey);

. . . . . . . . . . . .

End;

Destructor Tree.Free;// удаляет все элементы

Procedure Del(var p:Ttree);

begin

If (p<>Nil) then begin

Del(p^.A1);

Del(p^.A2);

Dispose(p);

p:=Nil;

end;

end;

begin Del(proot); inherited free; end;

Работа с деревом начинается с его создания и заканчивается освобождением памяти, например:

Var d1:Tree; c:Tinf; k:Tkey;

. . . . . . .

D1:=Tree.create; //используется конструктор из Tobject

//Здесь находятся процедуры работы с деревом:

D1.Add(c);

D1.poisk(k);

. . . . . .

D1.Free;

Обход бинарного дерева в симметричном порядке:

Листинг 7.6

Procedure Tree.Wrt1;

Procedure Wr(p:Ttree); //рекурсивный обход

begin

if p<>nil then

begin

Wr(p^.A1);

Print(p^.Inf);//печать или запись в файл ставится здесь

Wr(p^.A2);

end;

end;

begin p:=proot; wr(p) end;

При обходе бинарного дерва поиска этим методом будет напечатана информация в порядке возрастания ключа. Если в этом методе поменять местами А1иА2и назвать ееWrt2, то информация будет напечатана в порядке убывания ключа.

Нахождение элемента с заданным ключом k в двоичном дереве поиска:

Листинг 7.7

Function Tree.poisk(k:Tkey):TInf;

begin p:=Proot;

While(p<>nil) and (p^.Inf.key<>k) do

If k<p^.Inf.key then p:=p^.A1

else p:=p^.A2;

if p<>Nil then Result:=p^.Inf

else Print(Поиск без результата);

end;

Эффективность этого поиска O(lg2n)

Поиск информации с минимальным (максимальным) ключом:

Листинг 7.8

Function Tree.Mink:TInf;

begin p:=proot;

While p^.A1<>Nil do p:=p^.A1;

Result:=p^.Inf;

end;

При поиске максимального ключа нужно спуститься по правой ветке (Maxk: p^.A2<>Nil, p:=p^.A2) до самого правого листа.

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

Вначале напишем алгоритм создания нового листа дерева по адресу в указателе w. Затем напишем алгоритм поиска места добавления нового листа метод добавления нового листа с ключом, находящимся в поле Inf.key помещаемой информации Inf в дерево поиска сохраняя его свойства:

Листинг 7.9

Procedure Tree.Add(Inf:TInf);

Var bl:Boolean;

begin

New(w); // создание нового листа:

P^.Inf:=Inf;

P^.A1:=Nil; P^.A2:=Nil;

if proot=Nil then proot:=w

else begin // поиск места добавления листа:

p:=proot;

repeat

q:=p; //здесь q – указатель на предыдущий элемент

bl:=Inf.key<p^.Inf.key;

if bl then p:=p^.A1

else p:=p^.A2;

until p=Nil; // добавление листа

if bl then q^.A1:=w else q^.A2:=w;

end;

end;

Построение дерева поиска

Пусть имеется некоторый массив a:Tms из n значений данных с разными ключами (Tms=array[1..nr] of Tinf). Построение дерева поиска можно осуществить с помощью вышеописанных методов следующим образом:

Листинг 7.10

Procedure Tree.Make(a:Tms;n:word);

begin

For i:=1 to n do Add(a[i]);

end;

При случайном чередовании ключей в массиве а метод MakeB обычно формирует дерево неплохо сбалансированное. Однако, если ключи в исходном массиве а частично упорядочены, то получаемое таким образом дерево поиска оказывается сильно разбалансированным и его эффективность для организации поиска оказывается сравнимой с линейным поиском в массиве.

Этот способ построения дерева поиска можно использовать для печати в порядке возрастания элементов массива (например расположенного в файле). Для этого достаточно построить дерево с помощью метода MakeB и затем распечатать его методом Wrt1B.

Построение идеально сбалансированного дерева поиска для заданного отсортированного в порядке возрастания ключа массива данных a:Tms можно осуществить с помощью следующей рекурсивной процедуры (2 варианта):

Листинг 7.11

Procedure Tree.BLns(a:Tms;n:word);

Procedure BL(i,j:Word);