Новосибирский государственный технический университет

Кафедра вычислительной техники


Лабораторная работа №2

по дисциплине «Структуры и алгоритмы обработки данных»

"Нелинейные коллекции данных - сбалансированные деревья поиска"

Вариант:3

Группа: АМ-015

Бригада:1

Студенты: С.

Новосибирск 2002

Цель лабораторной работы

Реализация типовых коллекций данных в виде Абстрактных Типов Данных (АТД) на языке высокого уровня С++. Оценка и анализ эффективности алгоритмов реализации АТД. Формирование библиотеки разработанных АТД.

Задание

Спроектировать, реализовать и провести тестовые испытания АТД для нелинейной коллекции - "Сбалансированное дерево поиска". АТД " RB - дерево" - модификация АТД «Рекурсивное дерево двоичного поиска».

Описание иерархии классов

Классы «Дерво двоичного поиска» («BinTree») и «RB - дерево»(RBTree) cхожи по своей внутренней организации, но RBTree сбалансированное дерево 2-го поиска. Соответственно, необходима балансировка после операций вставки и удаления. Так же у RBTree есть своя особенность: каждый узел имеет цвет либо черный, либо красный.

RBTree обладает свойствами:

·  Каждый узел покрашен либо в черный, либо в красный цвет.

·  Листьями объявляются NIL-узлы (т. е. "виртуальные" узлы, наследники узлов, которые обычно называют листьями; на них "указывают" NULL указатели). Листья покрашены в черный цвет.

·  Если узел красный, то оба его потомка черны.

НЕ нашли? Не то? Что вы ищете?

·  На всех ветвях дерева, ведущих от его корня к листьям, число черных узлов одинаково.

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

Операция «Включение»

Чтобы вставить узел, мы сначала ищем в дереве место, куда его следует добавить. Новый узел всегда добавляется как лист, поэтому оба его потомка являются NIL-узлами и предполагаются черными. После вставки красим узел в красный цвет. После этого смотрим на предка и проверяем, не нарушается ли красно-черное свойство. Если необходимо, мы перекрашиваем узел и производим поворот, чтобы сбалансировать дерево.

Операция «Удаления» аналогична.

Формат АТД

Структура данных – «Рекурсивное дерево двоичного поиска». Модификация АТД – «RB - дерево».

АТД «Рекурсивное дерево двоичного поиска»

Данные:

Четыре указателя на объекты данного класса (правый, левый потомки; родитель, корень). Объект данных, которые хранятся в узле.

Три целых числа, указывающие на число рекурсивных вызовов трёх операций (включение, удаление, поиск по значению).

Операции:

Конструктор:

Начальные значения: значение данных (по умолчанию 15).

Процесс: установление всех счётчиков эл. действий в 0, все укзатели устанавливаются в NULL, кроме корня (он указывает на этот узел).

Size:

Вход: нет.

Предусловие: нет.

Процесс: вызывает рекурсивню функцию подсчета узлов, которая и возвращает значение количества узлов.

Выход: количество узлов

Постусловие: нет.

HighTree:

Вход: нет.

Предусловие: нет.

Процесс: вызывает рекурсивню функцию подсчета высоты, которая и возвращает значение высоты дерева.

Выход: высота дерева.

Постусловие: нет.

Empty:

Вход: нет

Предусловие: нет

Процесс: проверка на пустоту дерева

Выход: Перепенная типа boolean. True – дерево пусто. False – в дереве есть эл-ты.

Постусловие: нет.

PrintTree:

Вход: нет.

Предусловие: нет.

Процесс: вызывает рекурсивную функцию вывода дерева, которая и выводит его.

Выход: нет.

Постусловие: нет.

Clear:

Вход: нет.

Предусловие: нет.

Процесс: очистка дерева.

Выход: нет.

Постусловие: дерево пустое( корень не удаляется).

Include:

Вход: элемент для вставки в дерево.

Предусловие: нет.

Процесс: вызывает рекурсивную функцию вставки значения в дерево и она включает значение.

Выход: нет

Постусловие: дерево имеет новый элемент, если выполнены все условия; его размер увеличен на 1.

Delete:

Вход: значение по которому д. б. удалён элемент.

Предусловие: производим поиск в дереве и если такого элемента нет, то выбрасываем исключение.

Процесс: удаление элемента по значению.

Выход: сообщение исключения в случае неудачи.

Постусловие: дерево уменьшается на 1 элемент.

FindNod:

Вход: значение по которому будет производится поиск.

Предусловие: нет.

Процесс: вызов рекурсивной функции поиска, которая и ищет узел содерж. данный элемент.

Выход: возвращает узел содержащий данное значение в случае удачи или NULL в случае неудачи.

Постусловие: нет.

FindDat:

Вход: значение по которому будет производится поиск.

Предусловие: нет.

Процесс: вызывает рекурсивную функцию поиска, которая и ищет узел содерж. данный элемент.

Выход: возвращает 1 в случае удачи или -1 в случае неудачи.

Постусловие: нет.

GetStat:

Вход: три значения. Число операций вставки, удаления, поиска.

Предусловие: нет

Процесс: подсчитывается трудоемкость данных операций.

Выход: указатель на значения трудоёмкостей.

Постусловие: нет.

NullStat:

Вход: нет.

Предусловие: нет.

Процесс: очищает счётчики эл. операций.

Выход: нет.

Постусловие: нет.

SubInclude:

Вход: узел на данном шагу рекурсии, значение, которое включается.

Предусловие: нет.

Процесс: включение значение в дерево.

Выход: нет.

Постусловие: увеличивается число узлов в дереве, увеличивается счетчик «вставки».

SubDelete:

Вход: узел, который удаляется и его правый потомок.

Предусловие: нет.

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

Выход: обновленный, уже неудаляемый, узел.

Постусловие: количество узлов уменьшается на 1, увеличивается счетчик «удаления».

SubFindNod:

Вход: узел на данном шаге рекурсии, искомое значение для поиска.

Предусловие: если искомое значение совпадает со значением узла на данном шаге, то возвращается узел.

Процесс: рекурсивная функция поиска по значению.

Выход: указатель на узел с данным значением - удача, NULL - в случае неудачи.

Постусловие: увеличение счетчика «поиска».

SubFindDat:

Вход: узел на данном шаге рекурсии, искомое значение для поиска.

Предусловие: если искомое значение совпадает со значением узла на данном шаге, то возвращается 1.

Процесс: рекурсивная функция поиска по значению.

Выход: 1- в случае удачи, -1 неудачи.

Постусловие: нет.

SizeSub:

Вход: узел на данном шаге рекурсии.

Предусловие: пока узел не равен NULL.

Процесс: рекурсивная функция подсчета кол-ва узлов в дереве.

Выход: кол-во узлов.

Постусловие: нет.

HighTreeSub:

Вход: узел на данном шаге рекурсии.

Предусловие: пока узел не равен NULL.

Процесс: рекурсивная функция подсчета высоты дерева.

Выход: высота дерева.

Постусловие: нет.

PrintTreeSub:

Вход: узел на данном шаге рекурсии, число пробелов на данном шаге рекурсии.

Предусловие: пока узел не равен NULL.

Процесс: рекурсивная функция вывода узлов дерева.

Выход: нет.

Постусловие: нет.

ClearSub:

Вход: узел на данном шаге рекурсии.

Предусловие: пока узел не равен NULL.

Процесс: рекурсивная функция удаления узлов дерева.

Выход: нет.

Постусловие: все узлы, кроме корня, удалены.

АТД «Рекурсивное дерево двоичного поиска»

АТД «RB - дерево»

Данные:

Положительное целое число, указывающее на цвет узла.

Объект данного класса указывающего на корень.

Операции:

Конструктор:

Начальные значения: размер массива (по умолчанию 10).

Процесс: установление всех счётчиков эл. действий в 0, все укзатели устанавливаются в NULL, кроме корня (он указывает на этот узел), цвет устанавливается в черный.

Clear:

Вход: нет.

Предусловие: нет.

Процесс: очистка дерева.

Выход: нет.

Постусловие: дерево пустое( корень не удаляется).

Include:

Вход: элемент для вставки в дерево.

Предусловие: нет.

Процесс: вызывает рекурсивную функцию вставки значения в дерево и она включает значение, этот элемент окрашивается в черный цвет.

Выход: нет

Постусловие: дерево имеет новый элемент, если выполнены все условия; его размер увеличен на 1.

PrintTree:

Вход: нет.

Предусловие: нет.

Процесс: вызывает рекурсивную функцию вывода дерева, которая и выводит его.

Выход: нет.

Постусловие: нет.

RBFindNod:

Вход: значение по которому будет производится поиск.

Предусловие: нет.

Процесс: вызов рекурсивной функции поиска, которая и ищет узел содерж. данный элемент.

Выход: возвращает узел содержащий данное значение в случае удачи или NULL в случае неудачи.

Постусловие: нет.

Delete:

Вход: значение по которому д. б. удалён элемент.

Предусловие: производим поиск в дереве и если такого элемента нет, то выбрасываем исключение.

Процесс: удаление элемента по значению, балансировка и перекраска дерева.

Выход: сообщение исключения в случае неудачи.

Постусловие: дерево уменьшается на 1 элемент, увеличение счетчика «удаления».

DelRB:

Вход: удаляемый узел.

Предусловие: нет.

Процесс: функция менеджер. Делает «подготовительный этап» до функции перекраски и балансировки. Удаляет узел.

Выход: нет.

Постусловие: дерево уменьшается на 1 элемент, увеличение счетчика «удаления».

DelFix:

Вход: 2-а узла на данном этапе рекурсии(1- потомок удаляемого, 2-предок удяляемого).

Предусловие: нет.

Процесс: перекраска узлов и балансировка дерева.

Выход: нет.

Постусловие: изменение окраски узлов и взаимное расположение, увеличение счетчика «удаления».

SubInclude:

Вход: узел на данном этапе рекурсии и включаемое значение.

Предусловие: нет.

Процесс: включение нового узла в дерево и вызов функции перекраски и балансировки.

Выход: нет.

Постусловие: увеличение размера дерева, увеличение счетчика «вставки».

InsertFixUp:

Вход: включаемый узел.

Предусловие: выход из функции, если на данном этапе рекурсии узел является корнем или цвет предка черный.

Процесс: перекараска и балансировка дерева.

Выход: нет.

Постусловие: изменение окраски узлов и взаимное расположение, увеличение счетчика «вставки».

rotateRight:

Вход: узел относительно, которого производится вращение.

Предусловие: нет.

Процесс: вращение узлов вправо т. е. балансировка.

Выход: нет.

Постусловие: изменение взаиморасположения узлов.

rotateLeft:

Вход: узел относительно, которого производится вращение.

Предусловие: нет.

Процесс: вращение узлов влево т. е. балансировка.

Выход: нет.

Постусловие: изменение взаиморасположения узлов.

PrintTreeSub:

Вход: узел на данном шаге рекурсии, число пробелов на данном шаге рекурсии.

Предусловие: пока узел не равен NULL.

Процесс: рекурсивная функция вывода узлов дерева.

Выход: нет.

Постусловие: нет.

Конец АТД«RB - дерево».

Графики и таблицы с полученными оценками эффективности алгоритмов операций для наихудшего, наилучшего и среднего случаев функционирования АТД

N

OldSize

BinTree

RBTree

N NewSize

Find

Inc

Del

Med

Find

Inc

Del

Med

100

6

6

9

7

5

6

6

5

102

300

7

8

12

9

6

7

7

6

299

500

8

10

14

10

7

8

9

8

499

1000

10

12

16

12

7

9

12

9

1002

2500

11

12

19

14

9

10

14

11

2501

5000

13

14

22

16

10

11

15

11

4998

Количество операций =100

Find, Include, Delete – это количество попаданий в узел (рекурсивный вызов)/ кол-во операций соответственно. Mediana=(Find+Include+Delete)/3.

Сравнение операций RB и Bin деревьев

Из графиков видно, что наиболее трудоемкая СД является «BinTree», т. к. она несбалансированная. Соответственно, увеличивается число рекурсивных вызовов для того что бы попасть в вершину дерева.

Наиболее трудоемкая операция – удаление, т. к. функции удаления использует функцию поиска, то соответственно она зависит от реализации ф-ции поиска. Трудоемкости вставки и поиска приблизительно равны.

Текст программы:

template <class T> class BinTree

{

protected:

BinTree<T> *left;//левый потомок

BinTree<T> *right;//правый -\\-

BinTree<T> *parent;//родитель

BinTree<T> *broot;//корень

T dat; //данные

//счетчики рекурсивных вызовов

long del;//удаление

long ins;//вставка

long find;//поиск

public:

BinTree(T _dat=15)//конструктор. По умолчанию значение корня=15

{

dat=_dat;right=left=parent=NULL;

broot=this;//корень

del=ins=find=0;count=0;//обнуление

}

~BinTree()

{

del=ins=dat=0;

}

virtual int Size()//опрос количества узлов в дереве

{

return SizeSub(broot);

}

int HighTree()//высота дерева

{

return HighTreeSub(broot);

}

bool Empty()//проверка пустого дерева

{

if(broot->left==NULL && broot->right==NULL) return true;

return false;

}

virtual void PrintTree() //распичатка дерева

{

cout<<"This BST Struct\n\n";

PrintTreeSub(broot,1);

}

virtual void Clear()//очистка дерева

{

ClearSub(broot);

broot->left=NULL;//у корня нет потомков

broot->right=NULL;

}

virtual void Include(T _dat)//включение значения в дерево

{

SubInclude(broot,_dat);

}

virtual void Delete(T _dat)//удаление узла с этим значением

{

long oldfind=find;//запоминаем счетчик поиска

BinTree<T> *temp=FindNod(_dat);//получаем этот узел

del=del+(find-oldfind);//записываем разность в сч. удалений

find=oldfind;//восстанавливаем сч."поиска"

if(temp==NULL)throw " Ошибка! Узла с таким значением нет.";

//если значения нет, то ошибка

if(temp->left==NULL && temp->right==NULL)//если у него нет потомков

{

del++;

if(temp->parent->left==temp)//если это левый потомок

temp->parent->left=NULL;

else //если это правый потомок

temp->parent->right=NULL;

}

else

if(temp->left==NULL)//если нет левого потомка

{

del++;

if(temp->parent!=NULL)//если удаляем не root

{

temp->right->parent=temp->parent;

temp->parent->left=temp->right;

}

else//если удаляем root

{

temp->right->parent=NULL;

broot=temp->right;

}

}

else

if(temp->right==NULL)//если нет правого потомка

{

del++;

if(temp->parent!=NULL)//если удаляем не root

{

temp->left->parent=temp->parent;

temp->parent->left=temp->left;

}

else//если удаляем root

{

temp->left->parent=NULL;

broot=temp->left;

}

}

else

if(temp->right!=NULL && temp->left!=NULL)//если есть потомки

{

temp->right=SubDelete(temp->right, temp);

return;

}

if(this!=temp)delete temp;//удаляем этот узел

//мы же не можем удалить самого себя

}

BinTree<T>* FindNod(T _dat) //поиск по значению.

{//Удача - укзатель на узел содержащий данное значение

//не найден - -1

return SubFindNod(broot,_dat);

}

int FindDat(T _dat)//поиск по значению в дереве. 1- удача. -1- не найден.

{

return SubFindDat(broot,_dat);

}

virtual long * GetStat(long _del, long _ins, long _find)//получение статистики

{

//пользователь после тестирования должен удалить

//данные, иначе "лики памяти"

long *st=new long[4];

st[0]=del/_del;

st[1]=ins/_ins;

st[2]=find/_find;

st[3]=(del/_del+ins/_ins+find/_find)/3;

return st;

}

virtual void NullStat()//очищаем статистику

{

ins=del=find=0;

}

protected:// служебные рекурсивные функции

void SubInclude(BinTree<T> *temp, T _dat)//включение

{//вспомогательная рекурсивная функция

//включение в дерево

ins++;

if(temp->dat>_dat && temp->left==NULL)//если меньше и у него

{ //нет левого потомка

temp->left=new BinTree<T>(_dat);

temp->left->parent=temp;

return;

}

if(temp->dat<_dat && temp->right==NULL)//если больше и у него

{ //нет правого потомка

temp->right=new BinTree<T>(_dat);

temp->right->parent=temp;

return;

}

if(temp->dat>_dat)//если меньше, то влево

{

SubInclude(temp->left,_dat);

}

if(temp->dat<_dat)//если больше, то вправо

{

SubInclude(temp->right,_dat);

}

}

virtual BinTree<T>* SubDelete(BinTree<T> *temp, BinTree<T> *t0)

{ //вспомогательная рекурсивная функция

//перестройка потомков от удаляемого узла

del++;

if(temp->left!=NULL)

{

temp->left=SubDelete(temp->left, t0);

return temp;

}

t0->dat=temp->dat;

BinTree<T> * x=temp->right;

if(this!=temp)delete temp;//нельзя же удалить самого себя

return x;

}

virtual BinTree<T>* SubFindNod(BinTree<T> *temp, T _dat)//поиск по значению

{

//вспомогательная рекурсивная функция

//NULL - неудача. Узел - при удаче

if(temp->dat==_dat) return temp;//найден

if(temp->dat>_dat)//если меньше, то влево

{

if(temp->left==NULL)return NULL;//если до конца,

//и такого значения нет, то неудача

SubFindNod(temp->left,_dat);

}

else//если больше, то вправо

{

if(temp->right==NULL)return NULL;//если до конца,

//и такого значения нет, то неудача

SubFindNod(temp->right,_dat);

}

find++;

}

int SubFindDat(BinTree<T> *temp, T _dat)//поиск по значению

{ //вспомогательная рекурсивная функция

//1- удача -1- неудача

//аналогично функции SubFindNod

if(temp->dat==_dat) return 1;

if(temp->dat>_dat)

{

if(temp->left==NULL)return -1;

SubFindDat(temp->left,_dat);

}

else

{

if(temp->right==NULL)return NULL;

SubFindDat(temp->right,_dat);

}

}

int SizeSub(BinTree<T> *p)//подсчет числа вершин д. дерева

{

//вспомогательная рекурсивная функция

if (p==NULL) return 0;

return (1 + SizeSub(p->right) + SizeSub(p->left));

}

int HighTreeSub(BinTree<T> *p)//подсчет максимальной длины ветви.

{//вспомогательная рекурсивная функция

if (p==NULL) return 0;

int nr=HighTreeSub(p->right)+1;//вправо

int nl=HighTreeSub(p->left)+1;//потом влево

return nr>nl? nr : nl;//если nr>nl -->возвратить nr, иначе nl

}

void ClearSub(BinTree<T> *p)//очистка дерева

{//вспомогательная рекурсивная функция

if(p==NULL) return ;

ClearSub(p->left);//левые ветки

ClearSub(p->right);//правые ветки

if(this!=p)delete p;//не можем удалить сами себя

}

virtual void PrintTreeSub(BinTree<T> *p, int lvl)//распечатка ф-ии

{//вспомогательная рекурсивная функция

if(p==NULL) return ;

PrintTreeSub(p->right, lvl+1);

for(int i=0;i<lvl*2;i++)

{

cout<<" ";

}

cout<<p->dat<<'\n';

PrintTreeSub(p->left, lvl+1);

}};

typedef enum { BLACK, RED } RBTreeColor;//Задание цветов

template <class T> class RBTree: public BinTree<T>

{

int color;//цвет

RBTree<T> *root;//корень RB-дерева

public:

RBTree(T _dat=15)//конструктор доопределен.

{

dat=_dat;ins=del=find=0;

color=BLACK;//черный при сождании

root=this;

}

void Clear()

{ //Аналогично функции Clear()

ClearSub(root);

root->left=NULL;

root->right=NULL;

}

void Include(T _dat)//включение нового значения в RB-дерево

{

SubInclude(root,_dat);

root->color = BLACK;

}

void PrintTree()//вывод RB - дерева

{

cout<<"This RBTree Struct\n\n";

PrintTreeSub(root,1);

}

RBTree<T>* RBFindNod(T _dat)

{

return (RBTree<T>*)SubFindNod(root,_dat);//получаем этот узел

}

void Delete(T _dat)//удаляем RBT - Node по значению.

{ // в случае если такого значения нет, то выбрасываем исключение

long oldfind=find;//манипуляция со счетчиками

RBTree<T> *temp=(RBTree<T>*)SubFindNod(root,_dat);

del=del+(find-oldfind);

find=oldfind;

if(temp==NULL)throw " Ошибка! Узла с таким значением нет";

DelRB(temp);//если узел найден, то удаляем его

}

int Size()//размер RBTree

{

return SizeSub(root);

}

protected:

/******

* Находим удаляемый узел *

* Делаем балансировку и перекраску если это *

* необходимо. *

* Удаляем его *

*******/

void DelRB(BinTree<T> *d)

{

BinTree <T>*x, *y,*prev;

int g=1;

if (d==root) g=0;

if (d->left==NULL||d->right==NULL)

{

y = d;

}

else

{

y=d->right;

while (y->left!=NULL)

{

del++;

y=y->left;

}

}

if (y->left!=NULL)

x=y->left;

else

x=y->right;

prev=y->parent;

if(x)x->parent=y->parent;

if (y->parent)

if (y==y->parent->left)

y->parent->left=x;

else

y->parent->right=x;

else

root=(RBTree<T>*)x;

if (y!=d)d->dat=y->dat;

if (x&&y!=root && ((RBTree<T>*)y)->color==BLACK&&g)

{

DelFix((RBTree<T>*)x,(RBTree<T>*)prev);

if(x)((RBTree<T>*)x)->color=BLACK;

prev=prev->parent;

}

if(y!=this)delete ((RBTree<T>*)y);//не можем удалить сами себя

}

void DelFix(RBTree<T> *x, RBTree<T> *prev)

{

//функция балансировки и перекраски

del++;

if(x == root) return;

if(x&&((RBTree<T>*)x)->color==BLACK)return;

if (x==prev->left)

{

BinTree<T> *w=prev->right;

if(!w)return;

if (w&&((RBTree<T>*)w)->color==RED)

{

((RBTree<T>*)w)->color=BLACK;

((RBTree<T>*)prev)->color=RED;

if(w)rotateLeft((RBTree<T>*)prev);

if(prev!=NULL)w=prev->right;

}

if (w&&w->right && w->left&&((RBTree<T>*)w->left)->color==BLACK&&((RBTree<T>*)w->right)->color==BLACK)

{

((RBTree<T>*)w)->color=RED;

x=prev;

}

else

{

if(w&&w->right&&((RBTree<T>*)w->right)->color==BLACK)

{

if(w->left)((RBTree<T>*)w->left)->color=BLACK;

((RBTree<T>*)w)->color=RED;

rotateRight((RBTree<T>*)w);

if(prev!=NULL)w=prev->right;

}

if(w)((RBTree<T>*)w)->color=((RBTree<T>*)prev)->color;

((RBTree<T>*)prev)->color=BLACK;

if(w&&w->right)((RBTree<T>*)w->right)->color=BLACK;

if(w)rotateLeft((RBTree<T>*)prev);

x=root;

}

DelFix(x, prev);

}

else

{

BinTree <T>*w = prev->left;

if(!w)return;

if (w&&((RBTree<T>*)w)->color==RED)

{

((RBTree<T>*)w)->color=BLACK;

((RBTree<T>*)prev)->color=RED;

rotateRight((RBTree<T>*)prev);

if(prev!=NULL)w=prev->left;

}

if (w&&w->left&&w->right&&((RBTree<T>*)w->right)->color==BLACK&&((RBTree<T>*)w->left)->color==BLACK)

{

((RBTree<T>*)w)->color=RED;

x=prev;

}

else

{

if (w&&w->left&&((RBTree<T>*)w->left)->color==BLACK)

{

if(w->right)((RBTree<T>*)w->right)->color=BLACK;

((RBTree<T>*)w)->color=RED;

rotateLeft((RBTree<T>*)w);

if(prev!=NULL)w=prev->left;

}

if(w)((RBTree<T>*)w)->color=((RBTree<T>*)prev)->color;

((RBTree<T>*)prev)->color=BLACK;

if(w&&w->left)((RBTree<T>*)w->left)->color=BLACK;

rotateRight((RBTree<T>*)prev);

x=root;

}

DelFix(x, prev);

}

}

/******

* Находим место для узла и вставляем в дерево *

* Делаем балансировку и перекраску если это *

* необходимо *

*******/

void SubInclude(RBTree<T> *temp, T _dat)//включение значения

{

if(temp->dat>_dat && temp->left==NULL)

{

RBTree<T> *New=new RBTree<T>(_dat);//новый объект

temp->left=New;//установка связей с предком

temp->left->parent=temp;

New->color=RED;//красим в красный(по правилу RBTree)

InsertFixUp(New);//балансируем и красим, если необходимо

return ;

}

if(temp->dat<_dat && temp->right==NULL)

{

RBTree<T> *New=new RBTree<T>(_dat);

temp->right=New;//установка связей с предком

temp->right->parent=temp;

New->color=RED;//красим в красный(по правилу RBTree)

InsertFixUp(New);//балансируем и красим, если необходимо

return ;

}

if(temp->dat>_dat)//елси меньше, то влево

{

SubInclude((RBTree<T>*)temp->left,_dat);

}

if(temp->dat<_dat)//если больше, то вправо

{

SubInclude((RBTree<T>*)temp->right,_dat);

}

ins++;

}

//Рекурсивная ф-я перекраски и балансировки

void InsertFixUp(RBTree<T> *x)

{

ins++;

//условие выхода

if(!(x!= root && ((RBTree<T>*)x->parent)->color==RED)) return ;

if(x->parent == x->parent->parent->left)//левая ветвь

{

RBTree<T> *y = ((RBTree<T>*)x->parent->parent->right);

if(y!=NULL && y->color == RED)// "Дядя" - RED

{

((RBTree<T>*)x->parent)->color = BLACK;//цвет предка ЧЕРН.

y->color = BLACK;//Дядин цвет ЧЕРН.

((RBTree<T>*)x->parent->parent)->color = RED;

x=((RBTree<T>*)x->parent->parent);

InsertFixUp(x);//на 2-а узла выше

}

else // Дядя - BLACK

{

if (x == x->parent->right)

{

//делаем правым потомком

x = (RBTree<T>*)x->parent;

rotateLeft(x);

}

// перекраска и вращение

((RBTree<T>*)x->parent)->color = BLACK;

((RBTree<T>*)x->parent->parent)->color = RED;

rotateRight((RBTree<T>*)x->parent->parent);

InsertFixUp(x);

}

}

else // правая ветвь

{

// "зеркальный" код

RBTree<T> *y = (RBTree<T>*)x->parent->parent->left;

if (y!=NULL && y->color == RED)

{

// Дядя - RED

((RBTree<T>*)x->parent)->color = BLACK;

y->color = BLACK;

((RBTree<T>*)x->parent->parent)->color = RED;

x =(RBTree<T>*)x->parent->parent;

InsertFixUp(x);

}

else

{

// Дядя - BLACK

if (x == x->parent->left)

{

x =(RBTree<T>*) x->parent;

rotateRight(x);

}

((RBTree<T>*)x->parent)->color = BLACK;

((RBTree<T>*)x->parent->parent)->color = RED;

rotateLeft((RBTree<T>*)x->parent->parent);

InsertFixUp(x);

}

}

}

/*******

* Функции поворотов узлов *

/

void rotateLeft(RBTree <T>*t)//поворот влево

{

RBTree <T>*y=(RBTree<T>*)t->right;

if(y)t->right=y->left;

else t->right=NULL;

if(y&&y->left!=NULL)y->left->parent=t;

if(y!=NULL)y->parent=t->parent;

if(t->parent)

{

if (t==t->parent->left)

t->parent->left=y;

else

t->parent->right=y;

} else

{

root=y;

root->parent=0;

}

if(y)y->left = t;

if (t)t->parent=y;

}

void rotateRight(RBTree <T>*t)//поворот вправо

{

RBTree <T>*y=(RBTree<T>*)t->left;

if(y)t->left=y->right;

else t->left=NULL;

if (y&&y->right!=NULL)y->right->parent=t;

if (y!=NULL)y->parent=t->parent;

if (t->parent)

{

if (t==t->parent->right) t->parent->right=y;

else t->parent->left=y;

}

else

{

root=y;

root->parent=0;

}

if(y)y->right=t;

if(t!=NULL)t->parent=y;

}

void PrintTreeSub(RBTree<T> *t, int tmp)//Рекурсивная функция

{ //вывода RB - дерева

if(!t)return;

if(t->right)PrintTreeSub((RBTree<T>*)t->right, tmp+2);

if(t->color)SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED);

else SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE|FOREGROUND_INTENSITY);

for(int i=0;i<2*tmp;i++) cout<<' ';

cout<<t->dat<<" "<<endl;

if(t->left)PrintTreeSub((RBTree<T>*)t->left, tmp+2); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);

}};