Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Красно-черные деревья




Деки

Дек является особым видом очереди.

Дек (англ. deque – аббревиатура от double-ended queue, двухсторонняя очередь) – это структура данных, представляющая собой последовательность элементов, в которой можно добавлять и удалять в произвольном порядке элементы с двух сторон (рис. 3). Первый и последний элементы дека соответствуют входу и выходу дека.

       
   
 
 

 


Рис. 3. Дек и его организация

 

Частные случаи дека – это ограниченные деки:

· дек с ограниченным входом – из конца дека можно только извлекать элементы;

· дек с ограниченным выходом – в конец дека можно только добавлять элементы.

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

Однако применительно к деку целесообразно говорить не о начале и конце как в очереди, а о левом и правом конце.

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

struct Deque {

Double_List *Begin;//начало дека

Double_List *End; //конец дека

};

..........

Deque *My_Deque;

Основные операции, производимые с деком:

· создание дека;

· печать (просмотр) дека;

· добавление элемента в левый конец дека;

· добавление элемента в правый конец дека;

· извлечение элемента из левого конца дека;

· извлечение элемента из правого конца дека;

· проверка пустоты дека;

· очистка дека.

Реализацию этих операций приведем в виде соответствующих функций, которые, в свою очередь, используют функции операций с линейным двунаправленным списком.

//создание дека

void Make_Deque(int n, Deque* End_Deque){

Make_Double_List(n,&(End_Deque->Begin),NULL);

Double_List *ptr; //вспомогательный указатель

ptr = End_Deque->Begin;

while (ptr->Next!= NULL){

ptr = ptr->Next;

}

End_Deque->End = ptr;

}

 

//печать дека

void Print_Deque(Deque* Begin_Deque){

Print_Double_List(Begin_Deque->Begin);

}

 

//добавление элемента в правый конец дека

void Add_Right_Item_Deque(int NewElem, Deque* End_Deque){

End_Deque->End =Insert_Item_Double_List(End_Deque->End,2,NewElem);

End_Deque->End = End_Deque->End->Next;

}

 

//добавление элемента в левый конец дека

void Add_Left_Item_Deque(int NewElem, Deque* Begin_Deque){

Begin_Deque->Begin =

Insert_Item_Double_List(Begin_Deque->Begin, 1, NewElem);

}

 

//извлечение элемента из левого конца дека

int Extract_Left_Item_Deque(Deque* Begin_Deque){

int NewElem = NULL;

if (Begin_Deque->Begin!= NULL) {

NewElem = Begin_Deque->Begin->Data;

Begin_Deque->Begin=Delete_Item_Double_List(Begin_Deque->Begin,0);

//удаляем вершину

}

return NewElem;

}

 

//извлечение элемента из правого конца дека

int Extract_Right_Item_Deque(Deque* End_Deque){

int NewElem = NULL;

if (End_Deque->End!= NULL) {

NewElem = End_Deque->End->Data;

Delete_Item_Double_List(End_Deque->End, 1);

//удаляем вершину

}

return NewElem;

}

 

//проверка пустоты очереди

bool Empty_Deque(Deque* Begin_Deque){

return Empty_Double_List(Begin_Deque->Begin);

}

 

//очистка очереди

void Clear_Deque(Deque* Begin_Deque){

Delete_Double_List(Begin_Deque->Begin);

}

 

 

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

Красно-черное дерево (Red-Black-Tree, RB-Tree) – это бинарное дерево со следующими свойствами (рис. 4):

· каждая вершина должна быть окрашена либо в черный, либо в красный цвет;

· корень дерева должен быть черным;

· листья дерева должны быть черными и объявляться как NIL-вершины (NIL-узлы, то есть «виртуальные» узлы, наследники узлов, которые обычно называют листьями; на них «указывают» NULL указатели);

· каждый красный узел должен иметь черного предка;

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

 

 

 


Рис.4. Красно-черное дерево

 

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

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

Приведем функции следующих операций над красно-черными деревьями: создание дерева, печать (просмотр) дерева, обход дерева, проверка пустоты дерева и удаление дерева.

//создание красно-черного дерева

void Make_RBTree(RBTree** Node, int n){

int Data;

while (n > 0) {

cout << "Введите значение ";

cin >> Data;

Insert_Node(Node, Data);

n--;

}

}

 

//добавление узла в красно-черное дерево

void Insert_Node(RBTree** Node,int Data) {

RBTree **Curent, *Parent, *New_Node;

Curent = Node;

Parent = NIL;

// Поиск местоположения

while (*Curent!= NIL) {

Parent = (*Curent);

Curent = Data < (*Curent)->Data? &((*Curent)->Left): &((*Curent)->Right);

}

// Создание нового узла

New_Node = new RBTree();

New_Node->Data = Data;

New_Node->Parent = Parent;

New_Node->Left = NIL;

New_Node->Right = NIL;

New_Node->color = RED;

// Вставка элемента в дерево

if(Parent!= NIL){

if (Data < Parent->Data) Parent->Left = New_Node;

else Parent->Right = New_Node;

}

else (*Curent) = New_Node;

Insert_Fixup(Node, New_Node);

}

 

// Поддержка баланса дерева после вставки нового элемента

void Insert_Fixup(RBTree** Node,RBTree* New_Node){

RBTree* Current = New_Node;

// Проверка свойств дерева

while (Current!= *(Node) && Current->Parent->color == RED){

// если есть нарушение

if (Current->Parent == Current->Parent->Parent->Left) {

RBTree *ptr = Current->Parent->Parent->Right;

if (ptr->color == RED) {

Current->Parent->color = BLACK;

ptr->color = BLACK;

Current->Parent->Parent->color = RED;

Current = Current->Parent->Parent;

}

else {

if (Current == Current->Parent->Right) {

// сделать Current левым потомком

Current = Current->Parent;

Rotate_Left(Node,Current);

}

// перекрасить и повернуть

Current->Parent->color = BLACK;

Current->Parent->Parent->color = RED;

Rotate_Right(Node,Current->Parent->Parent);

}

}

else {

RBTree *ptr = Current->Parent->Parent->Left;

if (ptr->color == RED) {

Current->Parent->color = BLACK;

ptr->color = BLACK;

Current->Parent->Parent->color = RED;

Current = Current->Parent->Parent;

}

else {

if (Current == Current->Parent->Left) {

Current = Current->Parent;

Rotate_Right(Node,Current);

}

Current->Parent->color = BLACK;

Current->Parent->Parent->color = RED;

Rotate_Left(Node,Current->Parent->Parent);

}

}

}

(*Node)->color = BLACK;

}

 

//поворот узла Current влево

void Rotate_Left(RBTree** Node,RBTree *Current) {

RBTree *ptr = Current->Right;

Current->Right = ptr->Left;

if (ptr->Left!= NIL) ptr->Left->Parent = Current;

if (ptr!= NIL) ptr->Parent = Current->Parent;

if (Current->Parent!= NIL) {

if (Current == Current->Parent->Left)

Current->Parent->Left = ptr;

else

Current->Parent->Right = ptr;

}

else {

(*Node) = ptr;

}

ptr->Left = Current;

if (Current!= NIL) Current->Parent = ptr;

}

 

//поворот узла Current вправо

void Rotate_Right(RBTree** Node,RBTree *Current) {

RBTree *ptr = Current->Left;

Current->Left = ptr->Right;

if (ptr->Right!= NIL) ptr->Right->Parent = Current;

if (ptr!= NIL) ptr->Parent = Current->Parent;

if (Current->Parent!= NIL) {

if (Current == Current->Parent->Right)

Current->Parent->Right = ptr;

else

Current->Parent->Left = ptr;

}

else {

(*Node) = ptr;

}

ptr->Right = Current;

if (Current!= NIL) Current->Parent = ptr;

}

 

//печать красно-черного дерева

void Print_RBTree(RBTree* Node, int l){

int i;

if (Node!= NIL) {

Print_RBTree(Node->Right, l+1);

for (i=0; i< l; i++) cout << " ";

if (Node->color == RED)

SetConsoleTextAttribute(hStd,FOREGROUND_RED);

cprintf ("%4ld", Node->Data);

SetConsoleTextAttribute(hStd,atr);

Print_RBTree(Node->Left, l+1);

}

else cout << endl;

}

 

//прямой обход красно-черного дерева

void PreOrder_RBTree(RBTree* Node){

if (Node!= NIL) {

printf ("%3ld",Node->Data);

PreOrder_RBTree(Node->Left);

PreOrder_RBTree(Node->Right);

}

}

 

//обратный обход красно-черного дерева

void PostOrder_RBTree(RBTree* Node){

if (Node!= NIL) {

PostOrder_RBTree(Node->Left);

PostOrder_RBTree(Node->Right);

printf ("%3ld",Node->Data);

}

}

 

//симметричный обход красно-черного дерева

void SymmetricOrder_RBTree(RBTree* Node){

if (Node!= NIL) {

PostOrder_RBTree(Node->Left);

printf ("%3ld",Node->Data);

PostOrder_RBTree(Node->Right);

}

}

 

//проверка пустоты красно-черного дерева

bool Empty_RBTree(RBTree* Node){

return (Node == NIL? true: false);

}

 

//освобождение памяти, выделенной под красно-черное дерево

void Delete_RBTree(RBTree* Node){

if (Node!= NIL) {

Delete_RBTree(Node->Left);

Delete_RBTree(Node->Right);

delete(Node);

}

}

 




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


Дата добавления: 2014-01-04; Просмотров: 704; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.057 сек.