Professional Documents
Culture Documents
Lab 8
Lab 8
Звіт
з комп’ютерного практикуму №8
«Основні типи двійкові дерева пошуку»
з дисципліни «Теорія алгоритмів»
Бригада - 9
Варіант №3
Виконали:
студенти гр. ІС-33:
Гуминюк А.Г., Овсяник О.В.,
Путіловський Н.Т.
Викладач:
ст. вик. Дорошенко К.С.
Київ – 2024
Тема: Основні типи двійкові дерева пошуку
Мета роботи: Дослідження характеристик продуктивності основних типів
двійкових дерев пошуку.
Теоретичні дані
Дерево пошуку з мінімальною висотою називається збалансованим, тобто
таким, в якому висота лівого і правого піддерев відрізняються не більше ніж на
одиницю.
Збалансоване воно тому, що в такому дереві в середньому потрібно
витратити найменшу кількість операцій для пошуку.
Щоб дерево мало мінімальну висоту, кількість вузлів лівого і правого
піддерев повинні максимально наближатися один до одного.
Для побудови такого дерева можна використати наступний принцип:
– отримання відсортованого масиву;
– середина кожного підрозділу масиву стає кореневим вузлом, а ліва і
права частини - відповідними для нього піддеревами;
– оскільки масив відсортований, то отримане дерево відповідає
визначенню бінарного дерева пошуку.
Червоно-чорні дерева
Червоно-чорні дерева — різновид збалансованих дерев, в яких за
допомогою спеціальних трансформацій гарантується, що висота дерева h не
буде перевищувати O (log n).
Зважаючи на те, що час виконання основних операцій на бінарних
деревах (пошук, видалення, додавання елементу) є O(h), ці структури даних на
практиці є набагато ефективнішими, аніж звичайні бінарні дерева пошуку.
Бінарне дерево називається червоно-чорним, якщо воно має такі
властивості:
– кожна вершина або червона, або чорна;
– корінь дерева — чорний;
– кожний лист (NIL) — чорний;
– якщо вершина червона, обидві її дочірні вершини чорні (інакше, батько
червоної вершини — чорний);
– усі прості шляхи від будь-якої вершини до листів мають однакову
кількість чорних вершин.
Такі властивості надають червоно-чорному дереву додаткового
обмеження: найдовший шлях з кореня до будь-якого листа перевищує
найкоротший шлях не більше ніж вдвічі. В цьому сенсі таке дерево можна
назвати збалансованим. Зважаючи на те, що час виконання основних операцій з
бінарними деревами пошуку залежить від висоти, таке обмеження гарантує
їхню ефективність в найгіршому випадку, чого звичайні бінарні дерева
гарантувати не можуть.
Етапи розробки програми:
Постановка задачі.
Є певна кількість приладів. Кожний прилад має свою унікальну
потужність. Необхідно швидко знайти той прилад, що точно відповідає заданій
потужності заряду робота. Потужність задається з клавіатури. Від кожного
приладу є лише два шляхи для робота, але він точно знає де потужність буде
збільшуватися та зменшуватися в порівнянні з поточним. Якщо для робота не
буде знайдено відповідний пристрій, то для його порятунку треба терміново
додати такий пристрій. Для обох випадків побудувати шлях знаходження
пристрою. Якщо пристрій зламався, то він вже не має можливості допомогти
роботу, тому видаляється з мережи приладів та надається повідомлення про це.
Для кожного варіанту кількість елементів змінюється декілька разів
починаючи з 15 та йде на збільшення.
Модель.
Основні величини:
Назва Тип Опис
height int Висота вузла
Size Int Розмір
newhead Node* Вткористовується для повороту вузла
root Node* Вузол
left RBNode* Змінна для повороту вліво
right RBNode* Змінна для повороту вправо
key long long Ключ
Color Int Колір вузла в червоно-чорному дереві
Додаткові величини:
Назва Тип Опис
Змінна для обрахунку часу, за який виконується
exec_time unsigned int
програма
Розробка алгоритму.
Додавання вузла у збалансованому дереві:
#include "binarysearchtree.h"
#include <stack>
avl() {
root = nullptr;
}
private:
Node* root; // Кореневий вузол дерева
// Видалення вузла
Node* _erase(Node* head, long long x) {
if (head == nullptr) return nullptr;
if (x < head->key) {
head->left = _erase(head->left, x);
}
else if (x > head->key) {
head->right = _erase(head->right, x);
}
else {
Node* r = head->right;
if (head->right == nullptr) {
Node* l = head->left;
delete(head);
head = l;
}
else if (head->left == nullptr) {
delete(head);
head = r;
}
else {
while (r->left != nullptr) r = r->left;
head->key = r->key;
head->right = _erase(head->right, r->key);
}
}
// Балансування дерева
if (bal > 1) {
if (height(head->left) >= height(head->right)) {
return rightRotation(head);
}
else {
head->left = leftRotation(head->left);
return rightRotation(head);
}
}
else if (bal < -1) {
if (height(head->right) >= height(head->left)) {
return leftRotation(head);
}
else {
head->right = rightRotation(head->right);
return leftRotation(head);
}
}
return head;
}
if (k > x) {
path += "(Left) -> "; // Додаємо напрямок пошуку (ліворуч)
return _find(head->left, x, path); // Переміщуємося вліво і додаємо ключ до шляху
}
if (k < x) {
path += "(Right) -> "; // Додаємо напрямок пошуку (праворуч)
return _find(head->right, x, path); // Переміщуємося вправо і додаємо ключ до шляху
}
-------------------
#pragma once
#include "binarysearchtree.h"
RBNode* left;
RBNode* right;
RBNode* parent;
RBNode(long long k, int _col = 0, RBNode* _l = nullptr, RBNode* _r = nullptr, RBNode* _p = nullptr)
void updateSize() {
RBNode* getL() {
return this->left;
RBNode* getR() {
return this->right;
return this->key;
QColor getColor() {
};
private:
protected:
// Поворот вліво
ptr->right = right_child->left;
if (ptr->right != nullptr)
ptr->right->parent = ptr;
right_child->parent = ptr->parent;
if (ptr->parent == nullptr)
root = right_child;
ptr->parent->left = right_child;
else
ptr->parent->right = right_child;
right_child->left = ptr;
ptr->parent = right_child;
// Поворот вправо
ptr->left = left_child->right;
if (ptr->left != nullptr)
ptr->left->parent = ptr;
left_child->parent = ptr->parent;
if (ptr->parent == nullptr)
root = left_child;
ptr->parent->left = left_child;
else
ptr->parent->right = left_child;
left_child->right = ptr;
ptr->parent = left_child;
parent = ptr->parent;
grandparent = parent->parent;
if (parent == grandparent->left) {
if (getColor(uncle) == 0) {
setColor(uncle, 1);
setColor(parent, 1);
setColor(grandparent, 0);
ptr = grandparent;
else {
if (ptr == parent->right) {
rotateLeft(parent);
ptr = parent;
parent = ptr->parent;
rotateRight(grandparent);
std::swap(parent->color, grandparent->color);
ptr = parent;
else {
if (getColor(uncle) == 0) {
setColor(uncle, 1);
setColor(parent, 1);
setColor(grandparent, 0);
ptr = grandparent;
else {
if (ptr == parent->left) {
rotateRight(parent);
ptr = parent;
parent = ptr->parent;
rotateLeft(grandparent);
std::swap(parent->color, grandparent->color);
ptr = parent;
}
setColor(root, 1);
if (node == nullptr)
return;
if (node == root) {
root = nullptr;
return;
if (node == node->parent->left) {
node->parent->left = child;
if (child != nullptr)
child->parent = node->parent;
setColor(child, 1);
delete (node);
else {
node->parent->right = child;
if (child != nullptr)
child->parent = node->parent;
setColor(child, 1);
delete (node);
else {
parent = ptr->parent;
if (ptr == parent->left) {
sibling = parent->right;
if (getColor(sibling) == 0) {
setColor(sibling, 1);
setColor(parent, 0);
rotateLeft(parent);
else {
setColor(sibling, 0);
if (getColor(parent) == 0)
setColor(parent, 1);
else
setColor(parent, 2);
ptr = parent;
else {
if (getColor(sibling->right) == 1) {
setColor(sibling->left, 1);
setColor(sibling, 0);
rotateRight(sibling);
sibling = parent->right;
setColor(sibling, parent->color);
setColor(parent, 1);
setColor(sibling->right, 1);
rotateLeft(parent);
break;
else {
sibling = parent->left;
if (getColor(sibling) == 0) {
setColor(sibling, 1);
setColor(parent, 0);
rotateRight(parent);
else {
setColor(sibling, 0);
if (getColor(parent) == 0)
setColor(parent, 1);
else
setColor(parent, 2);
ptr = parent;
else {
if (getColor(sibling->left) == 1) {
setColor(sibling->right, 1);
setColor(sibling, 0);
rotateLeft(sibling);
sibling = parent->left;
setColor(sibling, parent->color);
setColor(parent, 1);
setColor(sibling->left, 1);
rotateRight(parent);
break;
if (node == node->parent->left)
node->parent->left = nullptr;
else
node->parent->right = nullptr;
delete(node);
setColor(root, 1);
}
int getColor(RBNode*& t) {
if (t == nullptr) return 1;
return t->color;
if (t == nullptr) return;
t->color = col;
if (root == nullptr)
return ptr;
root->left->parent = root;
root->right->parent = root;
return root;
// Видалення вузла
if (root == nullptr)
return root;
return root;
root->key = temp->key;
root->node = temp->node;
temp->node = _tmp;
ptr = ptr->left;
return ptr;
if (k > x) {
if (k < x) {
}
// Якщо знайдено потрібний елемент, додаємо його ключ і повертаємо його
return head;
return head->height;
public:
RBTree() {
root = nullptr;
n = 0;
// Функція вставки
fixInsert(node);
this->n++;
// Функція видалення
if (n == 2) {
if (data == root->key) {
auto t = root;
delete t;
root->color = 1;
root->parent = nullptr;
else {
else {
fixDelete(node);
n--;
// Функція пошуку
RBNode* getRoot() {
return root;
updateHeight(head->left);
updateHeight(head->right);
};
Перевірка програми.
Додавання елемента: Видалення
3
2,5
1,5
Час (с)
0,5
0
0 5 10 15 20 25
-0,5
Кількість елементів
2,5
1,5
Час (с)
0,5
0
0 5 10 15 20 25
-0,5
Кількість елементів
Пошук елемента:
Видалення
3
2,5
1,5
Час (с)
0,5
0
0 5 10 15 20 25
-0,5
Кількість елементів
Таблиця тестування.