Автоматизация операций над красно-чёрными деревьями



Для работы с двоичными деревьями важно уметь выполнять следующие операции:

- поиск по дереву;

- включение узла в дерево;

- удаление узла из дерева.

Именно эти операции будут представлены в программе.

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

Так же программа требует использования модуля CRT, который содержит библиотеку процедур, которые работают с клавиатурой и дисплеем.

В основе объектно-ориентированного программирования лежит идея объединения в одной структуре данных и действий, которые производятся над этими данными [4].

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

uses crt;

type

string_20 = string[20]; { Это - тип данных, хранимых в КЧД }

PTreeNode = ^TreeNode; { Узел дерева }

TreeNode = object

public

constructor init(_s: string; _parent: PTreeNode);

public

Color: integer; { Цвет листа: 0 = Черный, 1 = Красный }

left,right,parent,duplicates: PTreeNode; { Список дубликатов }

data_string: string_20;

deleted: boolean; { Флаг для "ленивого" удаления }

end;

RBTree = object

public

constructor init;

destructor done;

function Search(s: string): integer;

{ Возвращает +1, если строка присутствует в дереве, и -1 если ее там нет }

function SearchFirstMatch(s: string): PTreeNode;

{ Работает точно так же, как и Search, но возвращает указатель

  типа PTreeNode на первый подходящий элемент }

procedure Insert(s: string);

{ Добавляет новый элемент в дерево }

function InsertItem(s: string; node: PTreeNode): PTreeNode;

function Remove(s: string): boolean; { Удаляет заданную строку }

procedure SaveToFile(var f: text); { Сохраняет дерево в текстовый файл }

function LeftDepth: integer; { Находит глубину левого поддерева }

function RightDepth: integer; { Находит глубину правого поддерева }

function NumberOfLeaves(p: PTreeNode): integer;{ Находит число листьев в дереве }

public

root: PTreeNode;

private

procedure LeftRotation(node: PTreeNode);

procedure RightRotation(node: PTreeNode);

{ "Ротации" (повороты), используемые при вставке для балансировки дерева}

function TreeDepth(p: PTreeNode): integer;

{ Рекурсивная функция для нахождения глубины дерева, с корнем в P }

procedure DeleteTree(p: PTreeNode);

{ Деструктор вызывает эту процедуру для удаления дерева }

procedure SaveNode(level: integer;

         const node: PTreeNode; var f: text);

end;

Const { Цвета для узлов }

node_Red = 1;

node_Black = 0;

Объектно-ориентированное программирование предполагает образование нового типа данных – объект. Объект – это такая структура, компонентами которой являются взаимосвязанные данные различных типов и использующие эти данные процедуры и функции. Компоненты-данные называются полями объекта, а компоненты-процедуры и функции называются методами. Для обозначения типа «объект» в языке имеется служебное слово OBJECT. Каждая переменная типа «объект», содержащая виртуальные методы, должна инициализироваться отдельным вызовом конструктора. CONSTRUCTOR – конструктор, который выполняет установочную работу для механизма виртуальных методов [4].

Так же используется деструктор. DESTRUCTOR – специальный метод для освобождения динамических полей данных объекта, под которые выделялась дополнительная память при выполнении конструктора или иной процедуры инициализации, до уничтожения самого объекта.

После объявления переменных описываются все перечисленные процедуры и функции. Большая часть процедур и функций используется для того, чтобы построить красно-чёрное дерево в соответствии со всеми его основными свойствами [4].

constructor TreeNode.init(_s: string; _parent: PTreeNode);

begin

data_string := _s;

left := nil; right := nil;

parent := _parent; { Указатель на предка }

Duplicates := nil; { Изначально у узла нет дубликатов }

Color := node_Red; { Новые узлы становятся "Красными" }

Deleted := False; { Этот узел не удален }

end;

{Функция сравнения строк (ведомые пробелы не принимаются во внимание)}

function compare(s1, s2: string): integer;

procedure trim(var s: string);

begin

 while s[length(s)] = ' ' do delete(s, length(s), 1);

end;

begin

trim(s1); trim(s2);

if s1 < s2 then compare := -1

                else if s1 > s2 then compare := +1

                                    else compare := 0;

end;

constructor RBTree.init;

begin

root := nil;

end;

destructor RBTree.done;

begin

DeleteTree(Root); { DeleteTree освобождает динамическую память }

end;

procedure RBTree.DeleteTree(p: PTreeNode);

begin

if p <> nil then begin

DeleteTree(p^.Left); { Удалить левое поддерево }

DeleteTree(p^.Right); { Удалить правое поддерево }

DeleteTree(p^.Duplicates);

dispose(p);

end;

p := nil; { Узел более не используется }

end;

{ При вставке элемента могут произойти 3 случая:

1. Новый узел и его "дядя" - "Красные"

2. Новый узел красный, "дядя" - "Черный", и узел - левый потомок

3. Новый узел красный, "дядя" - "Черный", и узел - правый потомок }

procedure RBTree.Insert(s: string);{ Создает новый узел для хранения строки }

var

node, node_2: PTreeNode;

begin

node := InsertItem(s, root); { Вставить строку в дерево }

if node = nil then exit; { Изменять дерево не нужно }

while(node <> root) and (node^.parent^.color = node_Red) do begin

{ Проверяем, находится ли узел в левом поддереве }

if node^.parent = node^.parent^.parent^.left then begin

node_2 := node^.parent^.parent^.right; { Делаем node2 "дядей" нашего узла }

{ Если "дядя" красного цвета - это случай 1 }

if (node_2 <> nil) and (node_2^.Color = node_Red) then begin

   node^.parent^.Color := node_Black; { Изменяем цвет "родителя" на черный }

   node_2^.Color := node_Black;  { Изменяем цвет "дяди" на черный }

   node^.Parent^.Parent^.Color := node_Red; { Делаем "дедушку" красным }

   node := node^.Parent^.Parent;       { Двигаемся к вершине дерева для проведения дополнительных исправлений }

end

else begin { "дядя" - черного цвета, случай 2 или 3 }

   if Node = Node^.Parent^.Right then begin { Проверяем на случай №3 }

     Node := Node^.Parent; { Узел - правый потомок, это как раз случай №3 }

     LeftRotation(Node); { ... который требует левую "ротацию" }

   end;

   Node^.Parent^.Color := node_Black;  { Установка для случаев №2... }

   Node^.Parent^.Parent^.Color := node_Red; { ... и №3 }

   RightRotation(Node^.Parent^.Parent);

end;

end

else begin { узел - в правом поддереве }

node_2 := Node^.Parent^.Parent^.Left; { Делаем node2 "дядей" нашего узла }

{ Если "дядя" красного цвета - это случай 1 }

if(node_2 <> nil) and (node_2^.Color = node_Red) then begin

   Node^.Parent^.Color := node_Black;   { Изменяем цвет "родителя" на черный }

   Node_2^.Color := node_Black;       { Изменяем цвет "дяди" на черный }

     Node^.Parent^.Parent^.Color := node_Red; { Делаем "дедушку" красным }

   Node := Node^.Parent^.Parent;       { Двигаемся к вершине дерева... }

end

else begin { "дядя" - "черный", случай №2 или №3 }

   { Проверяем на случай №3 ("лево" и "право" обменяны местами) }

   if Node = Node^.Parent^.Left then begin

     Node := Node^.Parent; { Узел - левый потомок, это как раз случай №3...}

     RightRotation(Node); { ... который требует правую "ротацию" }

   end;

   Node^.Parent^.Color := node_Black;  { Установка для случаев №2... }

   Node^.Parent^.Parent^.Color := node_Red; { ... и №3 }

   LeftRotation(Node^.Parent^.Parent);

end;

end

end;

{ По правилу КЧД корень дерева должен быть черным }

Root^.Color := node_Black;

end;

function RBTree.InsertItem(s: string; node: PTreeNode): PTreeNode;

var

comparison: integer;

GreaterThanLeft, LessThanRight: boolean;

T: PTreeNode;

begin

if root = nil then begin

root := new(PTreeNode, init(s, nil)); { устанавливаем корень }

{ По правилу КЧД корень дерева должен быть черным }

root^.Color := node_Black;

InsertItem := root; exit

end;

while True do begin

comparison := compare(s, node^.data_string);

if node^.Deleted then begin

{ Для начала проверим, является ли узел "удаленным".

   Если это так, то существует возможность использовать "удаленный" узел для хранения новой записи, если она должна будет находиться между двумя "потомками" }

   if comparison=0 then begin

           node^.Deleted := false; { удел больше "удаленным" не считать }

           InsertItem := nil; exit

           end;

if node^.Left = nil then GreaterThanLeft := true

else

   {(В случае, если compare() < 0): строка не больше чем левый потомок, поэтому "удаленный" узел не может использоваться для хранения новой записи}

   GreaterThanLeft := (compare(s, node^.left^.data_string) > 0);

if node^.Right = nil then LessThanRight := true

else

    { (В случае, если compare() < 0): строка не больше чем правый потомок,

     поэтому "удаленный" узел не может использоваться для хранения новой записи }

     {??er??}

   LessThanRight := (compare(s, node^.right^.data_string) > 0);

if GreaterThanLeft and LessThanRight then begin

   { "удаленный" узел может использоваться для хранения новой записи }

   node^.data_string := s;

   node^.Deleted := false; { удел больше "удаленным" не считать }

   InsertItem := nil; exit

   { возвращаем NIL, чтобы избежать "ротаций" дерева, т.к. элемент, значение которого было изменено, находится на своем месте }

end;

end;

{ if comparison == 0 then begin

                       end }

if comparison < 0 then begin

{ Если Left пусто, помещаем новый узел туда }

if Node^.Left = nil then begin

   Node^.Left := new(PTreeNode, init(s, Node)); { Добавляем новый узел ... }

   InsertItem := Node^.Left;               { ... как левого потомка }

      exit

end

else Node := Node^.Left; { Проверить левое поддерево }

end

else

if comparison > 0 then begin

   { Если Right пусто, помещаем новый узел туда }

   if Node^.Right = nil then begin

     Node^.Right := new(PTreeNode, init(s, Node)); { Добавляем новый узел .}

     InsertItem := Node^.Right;               { ... как правого потомка }

     exit

   end

   else Node := Node^.Right; { Проверить правое поддерево }

end

else

    if Node^.Deleted = false then

   begin { узел - дубликат }

   Sound(220);   { Beep }

   Delay(1200);   { For 200 ms }

   NoSound;      { Relief! }

   writeln('!!!!!! Такой узел уже есть !!!!!!!');

   T := node;

   { находим конец списка дубликатов }

   while(T^.Duplicates <> nil) do T := T^.Duplicates;

   T^.Duplicates := new(PTreeNode, init(s, T));

   InsertItem := nil; exit

   {

   возвращаем NIL, чтобы избежать "ротаций" дерева, т.к.

   мы просто изменили список дубликатов

   }

end

{   else

   Node^.Deleted:=false;}

end;

end;

function RBTree.Remove(s: string): boolean;

var T, prev_node, node: PTreeNode;

begin

Remove := False;

Node := SearchFirstMatch(s); { Найдем подходящий узел в дереве }

if node = nil then exit; { Строка не была найдена - выход }

if node^.Duplicates <> nil then begin

{ если есть дубликаты - то один из дубликатов может занять место удаляемой записи }

T := node;

  while T^.Duplicates <> nil do begin

prev_node := T;

T := T^.Duplicates;

end;

node^.data_string := T^.data_string;

{ Копируем содержимое последнего дубликата в ту запись, которую будем удалять }

dispose(T);

prev_node^.Duplicates := nil;

{ "отсекаем" последний элемент списка дубликатов }

Remove := true; { удаление было успешным }

end

else

Node^.Deleted := true; { Помечаем узел как "удаленный" для "ленивого" удаления }

Remove := True

end;

function RBTree.Search(s: string): integer;

var

node: PTreeNode;

comparison: integer;

begin

Search := -1;

node := root;

while Node <> nil do begin

comparison := compare(s, node^.data_string);

if comparison < 0 then Node := Node^.Left {просматриваем левое поддерево}

else

{ if comparison < 0 then Node := Node^.Right ??err?? возможна ошибка }

if comparison > 0 then Node := Node^.Right { просматриваем правое поддерево }

else

   if Node^.Deleted then exit

     { если узел помечен на удаление - то не принимать его во внимание, выход }

   else begin

     { Строка найдена }

     search := 1; exit

   end;

end;

{ Запись не найдена }

end;

function RBTree.SearchFirstMatch(s: string): PTreeNode;

{ Возвращает указатель на первый узел, хранящий заданную строку }

var

node: PTreeNode;

comparison: integer;

begin

SearchFirstMatch := nil;

node := root;

while Node <> nil do begin

comparison := compare(s, node^.data_string);

if comparison < 0 then Node := Node^.Left {просматриваем левое поддерево}

else

if comparison > 0 then Node := Node^.Right { просматриваем правое поддерево }

else

   if Node^.Deleted then exit

     { если узел помечен на удаление - то не принимать его во внимание, выход }

   else begin

     { Строка найдена }

     SearchFirstMatch := node; exit

   end;

end;

end;

procedure RBTree.SaveToFile(var f: text);

{ сохраняет узлы в Прямом (нисходящем) порядке }

begin

{ Вызываем рекурсию }

SaveNode(0, root, f);

end;

procedure RBTree.SaveNode(level: integer;

     const node: PTreeNode; var f: text);

const

_color: array[0 .. 1] of char = ('B', 'R');

begin

if node <> nil then begin

{ if not node^.Deleted then begin }

if _color[node^.Color]='B' then TextColor(BLACK)

                             else TextColor(RED);

if node^.Deleted then TextBackground(BLUE);

write(f, '':3*level,

     { node^.data_string + ' ('+_color[node^.Color]+')'); }

      node^.data_string );

TextBackground(WHITE);

TextColor(GREEN);

writeln(f,'');

{ end; }

SaveNode(level + 1, node^.Left, f); { Сохраним узлы левого поддерева }

SaveNode(level + 1, node^.Right, f); { Сохраним узлы правого поддерева }

end;

end;

function RBTree.LeftDepth: integer;

begin

LeftDepth := TreeDepth(Root^.Left); { Измеряем левое поддерево }

end;

function RBTree.RightDepth: integer;

begin

RightDepth := TreeDepth(Root^.Right); { Измеряем правое поддерево }

end;

function RBTree.TreeDepth(p: PTreeNode): integer;

var _left, _right: integer;

begin

_left := 0; _right := 0;

if p^.Left <> nil then

_left := TreeDepth(p^.Left); { Взять глубину левого поддерева }

if p^.Right <> nil then

_right := TreeDepth(p^.Right); { Взять глубину правого поддерева }

if _left > _right then { проверяем, какое поддерево "глубже" }

TreeDepth := _left + 1 { вернем глубину левого поддерева + 1 }

else

TreeDepth := _right + 1; { вернем глубину правого поддерева + 1 }

end;

function RBTree.NumberOfLeaves(p: PTreeNode): integer;

var total: integer;

begin

NumberOfLeaves := 1;

total := 0;

if (p^.Left = nil) and (p^.Right = nil) then exit; { узел является "листом" }

{ считаем число листьев в левом поддереве }

if p^.Left <> nil then inc(total, NumberOfLeaves(p^.Left));

{ считаем число листьев в правом поддереве }

if p^.Right <> nil then inc(total, NumberOfLeaves(p^.Right));

NumberOfLeaves := total;

{ и возвращаем общее количество листьев в дереве }

end;

procedure RBTree.LeftRotation(node: PTreeNode);

var Right: PTreeNode;

begin

Right := node^.Right; { hold node's right child }

{ make the node's right child its right child's left child }

node^.Right := Right^.Left;

if Right^.Left <> nil then

Right^.Left^.Parent := Node; { point the child to its new parent }

if Right <> nil then

Right^.Parent := Node^.Parent; { point the child to its new parent }

if Node^.Parent <> nil then begin { if node is not the root }

if Node = Node^.Parent^.Left then { if node is a left child }

Node^.Parent^.Left := Right { make node's right child its parent's left child }

else

Node^.Parent^.Right := Right; {make node's right child its parent's right child }

end

else

Root := Right; { node's right child is now the root }

Right^.Left := Node; { node becomes its right child's left child }

if Node <> nil then

Node^.Parent := Right; { point node to its new parent }

end;

procedure RBTree.RightRotation(node: PTreeNode);

var Left: PTreeNode;

begin

Left := node^.Left; { hold node's left child }

{ make the node's left child its left child's right child }

Node^.Left := Left^.Right;

if Left^.Right <> nil then

Left^.Right^.Parent := Node; { point the child to its new parent }

if Left <> nil then

Left^.Parent := Node^.Parent; { point the child to its new parent }

if Node^.Parent <> nil then begin { if node is not the root }

if Node = Node^.Parent^.Right then { if node is a right child }

Node^.Parent^.Right := Left { make node's left child its parent's right child }

else

Node^.Parent^.Left := Left; { make node's left child its parent's left child }

end

else

Root := Left; { node's left child is now the root }

Left^.Right := Node; { node becomes its left child's right child }

if Node <> nil then

Node^.Parent := Left; { point node to its new parent }

end;

Далее следует собственно, программа, иллюстрирующая использование КЧД.

var

console: text;

s: string_20;

tree: RBTree;

begin

assigncrt(console);

rewrite(console);

TextBackground(WHITE);

TextColor(GREEN);

tree.init; 

repeat

writeln('1 – Построение дерева');

writeln('2 - Поиск');

writeln('3 – Показ дерева');

writeln('4 – Удаление узла');

writeln('9 - Выход');

readln(s);

 if ( s='1') then begin

   repeat

   write('enter string (20 chars max): '); readln(s);

       if s <> '' then begin

             tree.insert(s);

             Writeln('__________________________________________');

             tree.SaveToFile(console); { Выводим дерево на консоль }

             writeln('__________________________________________');

                       end;

   until s = '';

   end;

if ( s='3') then begin

             Writeln('**');

             tree.SaveToFile(console);

             Writeln('**');

             end;

if ( s='4') then begin

             write('enter string (20 chars max): '); readln(s);

             Write('узел ');Write(s);

             if tree.search(s)=1 then begin

                                      tree.Remove(s);

                                      writeln('удалён');

                                      tree.SaveToFile(console);

                                      end

                                 else writeln('не найден');

             Writeln('**');

             end;

if ( s='2') then begin

             write('enter string (20 chars max): '); readln(s);

             Write('узел');Write(s);

             if tree.search(s)=1 then writeln('найден')

                                 else writeln('не найден');

             Writeln('**');

             end;

until s = '9';

tree.SaveToFile(console);

{ Проверяем работу Search }

if tree.search('four') = 1 then writeln('found')

else writeln('not found');

{ Проверяем работу Remove }

tree.Remove('four');

tree.SaveToFile(console);

tree.done;

close(console);

end.

 


Заключение

В процессе выполнения работы были решены следующие задачи:

· ра ссмотрены красно-чёрные деревья и их свойства;

· изучены основные операции над красно-чёрными деревьями;

· представлена реализация основных операций над красно-чёрными деревьями на алгоритмическом языке;

· проиллюстрированы примеры красно-чёрных деревьев, а так же операции над ними;

· произведена автоматизация основных операций над красно-чёрными деревьями.

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

Красно-чёрные деревья составляют неотъемлемую часть современного информационного пространства, а также имеют широкую сферу применения. Поэтому изучение красно-чёрных деревьев, их основных свойств и операций над ними помогает изучить сферу их использования.


список литературы:

1. АЛГОРИТМЫ МЕТОДЫ ИСХОДНИКИ[электронный ресурс]. – Режим доступа: http://algolist.manual.ru/ds/rbtree.php.

2. Кнут Д.Э. Искусство программирования. Том 2. Получисленные алгоритмы: Пер. с англ. - М.: «Вильямс», 2000. — 682с.

3. Кормен, Томас X., Лейзерсон, Чарльз И., Ривест, Рональд Л., Штайн, Клиффорд. Алгоритмы: построение и анализ, 2-е издание. : Пер. с англ. - М.: Издательский дом "Вильяме", 2005. - 1296 с.: ил. - Парал. тит. англ.

4. Поляков Д.Б., Круглов И.Ю.. Программирование в среде Турбо Паскаль (версия 5.5): Справ.-метод. пособие. – М.: Изд-во МАИ, 1992. – 576 с.

5. [электронный ресурс]. – Режим доступа: http://mathc.chat.ru/a3/articl03.htm.

6. Pascal Page[электронный ресурс]. – Режим доступа: http://volvo71.narod.ru/faq_folder/rb_tree.htm.

 


Приложение 1. Листинг программы

Program rbtree_k;

uses crt;

type

string_20 = string[20];

PTreeNode = ^TreeNode;

TreeNode = object

public

constructor init(_s: string; _parent: PTreeNode);

public

Color: integer;

left,right,parent,duplicates: PTreeNode;

data_string: string_20;

deleted: boolean;

end;

RBTree = object

public

constructor init;

destructor done;

function Search(s: string): integer;   

function SearchFirstMatch(s: string): PTreeNode;

procedure Insert(s: string);

function InsertItem(s: string; node: PTreeNode): PTreeNode;

function Remove(s: string): boolean;

procedure SaveToFile(var f: text);

  function LeftDepth: integer;

function RightDepth: integer;

function NumberOfLeaves(p: PTreeNode): integer;

public

root: PTreeNode;

private

procedure LeftRotation(node: PTreeNode);

procedure RightRotation(node: PTreeNode);

function TreeDepth(p: PTreeNode): integer;

procedure DeleteTree(p: PTreeNode);

procedure SaveNode(level: integer;

         const node: PTreeNode; var f: text);

end;

Const

node_Red = 1;

node_Black = 0;

constructor TreeNode.init(_s: string; _parent: PTreeNode);

begin

data_string := _s;

left := nil; right := nil;

parent := _parent;

Duplicates := nil;

Color := node_Red;

Deleted := False;

end;

function compare(s1, s2: string): integer;

procedure trim(var s: string);

begin

while s[length(s)] = ' ' do delete(s, length(s), 1);

end;

begin

trim(s1); trim(s2);

if s1 < s2 then compare := -1

                else if s1 > s2 then compare := +1

                                   else compare := 0;

end;

constructor RBTree.init;

begin

root := nil;

end;

destructor RBTree.done;

begin

DeleteTree(Root);

end;

procedure RBTree.DeleteTree(p: PTreeNode);

begin

if p <> nil then begin

DeleteTree(p^.Left);

DeleteTree(p^.Right);

DeleteTree(p^.Duplicates);

dispose(p);

end;

p := nil;

end;

procedure RBTree.Insert(s: string);

var

node, node_2: PTreeNode;

begin

node := InsertItem(s, root);

if node = nil then exit;

while(node <> root) and (node^.parent^.color = node_Red) do begin

if node^.parent = node^.parent^.parent^.left then begin

node_2 := node^.parent^.parent^.right;

if (node_2 <> nil) and (node_2^.Color = node_Red) then begin

   node^.parent^.Color := node_Black;

   node_2^.Color := node_Black;

   node^.Parent^.Parent^.Color := node_Red;

   node := node^.Parent^.Parent;

end

else begin

   if Node = Node^.Parent^.Right then begin

     Node := Node^.Parent;

     LeftRotation(Node);

   end;

   Node^.Parent^.Color := node_Black;

   Node^.Parent^.Parent^.Color := node_Red;

   RightRotation(Node^.Parent^.Parent);

end;

end

else begin

node_2 := Node^.Parent^.Parent^.Left;

if(node_2 <> nil) and (node_2^.Color = node_Red) then begin

   Node^.Parent^.Color := node_Black;

   Node_2^.Color := node_Black;

   Node^.Parent^.Parent^.Color := node_Red;

   Node := Node^.Parent^.Parent;

end

else begin

   if Node = Node^.Parent^.Left then begin

     Node := Node^.Parent;

     RightRotation(Node);

   end;

   Node^.Parent^.Color := node_Black;

   Node^.Parent^.Parent^.Color := node_Red;

   LeftRotation(Node^.Parent^.Parent);

end;

end

end;

Root^.Color := node_Black;

end;

function RBTree.InsertItem(s: string; node: PTreeNode): PTreeNode;

var

comparison: integer;

GreaterThanLeft, LessThanRight: boolean;

T: PTreeNode;

begin

if root = nil then begin

root := new(PTreeNode, init(s, nil));

root^.Color := node_Black;

InsertItem := root; exit

end;

while True do begin

comparison := compare(s, node^.data_string);

if node^.Deleted then begin

   if comparison=0 then begin

           node^.Deleted := false;

           InsertItem := nil; exit

           end;

 if node^.Left = nil then GreaterThanLeft := true

    else GreaterThanLeft := (compare(s, node^.left^.data_string) > 0);

if node^.Right = nil then LessThanRight := true

    else LessThanRight := (compare(s, node^.right^.data_string) > 0);

if GreaterThanLeft and LessThanRight then begin

   node^.data_string := s;

   node^.Deleted := false;

   InsertItem := nil; exit

end;

end;

if comparison < 0 then begin

if Node^.Left = nil then begin

   Node^.Left := new(PTreeNode, init(s, Node));

   InsertItem := Node^.Left;

   exit

end

else Node := Node^.Left;

end

else

if comparison > 0 then begin

   if Node^.Right = nil then begin

     Node^.Right := new(PTreeNode, init(s, Node));

     InsertItem := Node^.Right;

     exit

   end

   else Node := Node^.Right;

end

else

   if Node^.Deleted = false then begin

     Sound(220);

     Delay(1200);

     NoSound;

     writeln('!!!!!! Такой узел уже есть !!!!!!!');

     T := node;

     while(T^.Duplicates <> nil) do T := T^.Duplicates;

     T^.Duplicates := new(PTreeNode, init(s, T));

     InsertItem := nil; exit

end

end;

end;

function RBTree.Remove(s: string): boolean;

var T, prev_node, node: PTreeNode;

begin

Remove := False;

Node := SearchFirstMatch(s);

if node = nil then exit;

if node^.Duplicates <> nil then begin

T := node;

while T^.Duplicates <> nil do begin

prev_node := T;

T := T^.Duplicates;

end;

node^.data_string := T^.data_string;

dispose(T);

prev_node^.Duplicates := nil;

Remove := true;

end

else

Node^.Deleted := true;

Remove := True

end;

function RBTree.Search(s: string): integer;

var

node: PTreeNode;

comparison: integer;

begin

Search := -1;

node := root;

while Node <> nil do begin

comparison := compare(s, node^.data_string);

if comparison < 0 then Node := Node^.Left

 else if comparison > 0 then Node := Node^.Right

else if Node^.Deleted then exit

   else begin

     search := 1; exit

   end;

end;

end;

function RBTree.SearchFirstMatch(s: string): PTreeNode;

var

node: PTreeNode;

comparison: integer;

begin

SearchFirstMatch := nil;

node := root;

while Node <> nil do begin

comparison := compare(s, node^.data_string);

if comparison < 0 then Node := Node^.Left

else if comparison > 0 then Node := Node^.Right

else if Node^.Deleted then exit

   else begin

     SearchFirstMatch := node; exit

   end;

end;

end;

procedure RBTree.SaveToFile(var f: text);

begin

SaveNode(0, root, f);

end;

procedure RBTree.SaveNode(level: integer;

     const node: PTreeNode; var f: text);

const

_color: array[0 .. 1] of char = ('B', 'R');

begin

if node <> nil then begin

if _color[node^.Color]='B' then TextColor(BLACK)

                             else TextColor(RED);

if node^.Deleted then TextBackground(BLUE);

write(f, '':3*level,node^.data_string );

TextBackground(WHITE);

TextColor(GREEN);

writeln(f,'');

SaveNode(level + 1, node^.Left, f);

SaveNode(level + 1, node^.Right, f);

end;

end;

function RBTree.LeftDepth: integer;

begin

LeftDepth := TreeDepth(Root^.Left);

end;

function RBTree.RightDepth: integer;

begin

RightDepth := TreeDepth(Root^.Right);}

end;

function RBTree.TreeDepth(p: PTreeNode): integer;

var _left, _right: integer;

begin

_left := 0; _right := 0;

if p^.Left <> nil then _left := TreeDepth(p^.Left);

if p^.Right <> nil then _right := TreeDepth(p^.Right);

if _left > _right then TreeDepth := _left + 1

else TreeDepth := _right + 1;

end;

function RBTree.NumberOfLeaves(p: PTreeNode): integer;

var total: integer;

begin

NumberOfLeaves := 1;

total := 0;

if (p^.Left = nil) and (p^.Right = nil) then exit;

if p^.Left <> nil then inc(total, NumberOfLeaves(p^.Left));

if p^.Right <> nil then inc(total, NumberOfLeaves(p^.Right));

NumberOfLeaves := total;

end;

procedure RBTree.LeftRotation(node: PTreeNode);

var Right: PTreeNode;

begin

Right := node^.Right;

node^.Right := Right^.Left;

if Right^.Left <> nil then

Right^.Left^.Parent := Node;

if Right <> nil then

Right^.Parent := Node^.Parent;

if Node^.Parent <> nil then begin

if Node = Node^.Parent^.Left then Node^.Parent^.Left := Right

else Node^.Parent^.Right := Right;

end

else Root := Right;

Right^.Left := Node;

if Node <> nil then Node^.Parent := Right;

end;

procedure RBTree.RightRotation(node: PTreeNode);

var Left: PTreeNode;

begin

Left := node^.Left;

Node^.Left := Left^.Right;

if Left^.Right <> nil then Left^.Right^.Parent := Node;

if Left <> nil then Left^.Parent := Node^.Parent;

if Node^.Parent <> nil then begin

if Node = Node^.Parent^.Right then Node^.Parent^.Right := Left

else Node^.Parent^.Left := Left;

end

else Root := Left;

Left^.Right := Node;

if Node <> nil then Node^.Parent := Left;

end;

var

console: text;

s: string_20;

tree: RBTree;

begin

assigncrt(console);

rewrite(console);

TextBackground(WHITE);

TextColor(GREEN);

tree.init;

repeat

writeln('1 – Построение дерева');

writeln('2 - Поиск');

writeln('3 – Показ дерева');

writeln('4 – Удаление узла');

writeln('9 - Выход');

readln(s);

if ( s='1') then begin

   repeat

   write('enter string (20 chars max): '); readln(s);

       if s <> '' then begin

             tree.insert(s);

             Writeln('__________________________________________');

             tree.SaveToFile(console); { Выводим дерево на консоль }

             writeln('__________________________________________');

                       end;

   until s = '';

   end;

if ( s='3') then begin

             Writeln('**');

             tree.SaveToFile(console);

             Writeln('**');

             end;

if ( s='4') then begin

             write('enter string (20 chars max): '); readln(s);

             Write('node ');Write(s);

             if tree.search(s)=1 then begin

                                      tree.Remove(s);

                                      writeln(' удалён');

                                      tree.SaveToFile(console);

                                      end

                                 else writeln(' не найден');

             Writeln('**');

             end;

if ( s='2') then begin

             write('enter string (20 chars max): '); readln(s);

             Write('node ');Write(s);

             if tree.search(s)=1 then writeln(' найден')

                                 else writeln(' не найден');

             Writeln('**');

             end;

until s = '9';

tree.SaveToFile(console);

{ Проверяем работу Search }

if tree.search('four') = 1 then writeln('found')

else writeln('not found');

{ Проверяем работу Remove }

tree.Remove('four');

tree.SaveToFile(console);

tree.done;

close(console);

end.


Дата добавления: 2020-12-12; просмотров: 101; Мы поможем в написании вашей работы!

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






Мы поможем в написании ваших работ!