diff --git a/3sem/data structures and algos/06/program.cpp b/3sem/data structures and algos/06/program.cpp new file mode 100644 index 0000000..3301661 --- /dev/null +++ b/3sem/data structures and algos/06/program.cpp @@ -0,0 +1,535 @@ +// dsaa_06.cpp +// Горбацевич Андрей +#include +#include + + +inline void time_passed(std::chrono::high_resolution_clock::time_point start, double& holder) { + auto stop = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(stop - start); + holder = duration.count(); +} + +#define BLACK 0u +#define RED 1u + +class RBTree { +public: + struct Node { + Node *parent = nullptr; + Node *left = nullptr; + Node *right = nullptr; + + unsigned int color : 1 = BLACK; + int val = -1; + }; + +private: + Node *root; + + static Node* parent(Node *n) { + return n->parent; + } + + static Node* sibling(Node *n) { + auto p = RBTree::parent(n); + + if (p != nullptr) { + return n == p->left? p->right : p->left; + } + return nullptr; + } + + static Node* parent_sibling(Node *n) { + return RBTree::sibling(RBTree::parent(n)); + } + + static void rotate_left(Node *n) { + auto nm = n->right; + auto p = RBTree::parent(n); + + n->right = nm->left; + nm->left = n; + n->parent = nm; + if (n->right != nullptr) { + n->right->parent = n; + } + + if (p != nullptr) { + if (n == p->left) { + p->left = nm; + } + else if (n == p->right) { + p->right = nm; + } + } + + nm->parent = p; + } + + static void rotate_right(Node *n) { + auto nm = n->left; + auto p = RBTree::parent(n); + + n->left = nm->right; + nm->right = n; + n->parent = nm; + if (n->left != nullptr) { + n->left->parent = n; + } + + if (p != nullptr) { + if (n == p->left) { + p->left = nm; + } + else if (n == p->right) { + p->right = nm; + } + } + + nm->parent = p; + } + + void _insert_rec(Node *sub_root, Node *n) { + if (sub_root != nullptr) { + if (n->val < sub_root->val) { + if (sub_root->left != nullptr) { + this->_insert_rec(sub_root->left, n); + return; + } + else { + sub_root->left = n; + } + } + else { + if (sub_root->right != nullptr) { + this->_insert_rec(sub_root->right, n); + return; + } + else { + sub_root->right = n; + } + } + } + + n->parent = sub_root; + n->left = n->right = nullptr; + n->color = RED; + } + + void _fix_tree(Node *n) { + if (n->color != BLACK && RBTree::parent(n) == nullptr) { + // at the top, need to repaint + n->color = BLACK; + } + else if (RBTree::parent(n)->color == BLACK) { + // ok + return; + } + else if (RBTree::parent_sibling(n) != nullptr && RBTree::parent_sibling(n)->color == RED) { + // if parent and it's sibling red, then we can repaint them black and recursively repaint grandparent + RBTree::parent(n)->color = BLACK; + RBTree::parent_sibling(n)->color = BLACK; + RBTree::parent(RBTree::parent(n))->color = RED; + _fix_tree(RBTree::parent(RBTree::parent(n))); + } + else { + // it may happen what parent.color != parent_sibling.color, then we can rotate twice to fix that and retain + // structure + auto p = RBTree::parent(n); + auto gp = RBTree::parent(p); + + if (n == p->right && p == gp->left) { + RBTree::rotate_left(p); + n = n->left; + } else if (n == p->left && p == gp->right) { + RBTree::rotate_right(p); + n = n->right; + } + + // rotating second time, thus getting everything in order + p = RBTree::parent(n); + gp = RBTree::parent(p); + + if (n == p->left) { + RBTree::rotate_right(gp); + } + else { + RBTree::rotate_left(gp); + } + p->color = BLACK; + gp->color = RED; + } + } + + void _print_tree(Node *n) { + if (n == nullptr) { + return; + } + + printf(" %d\n", n->val); + + if (n->left != nullptr) { + printf(" %d -> %d\n", n->val, n->left->val); + this->_print_tree(n->left); + } + + if (n->right != nullptr) { + printf(" %d -> %d\n", n->val, n->right->val); + this->_print_tree(n->right); + } + } + +public: + bool contains(int value) { + auto cn = this->root; + + while (cn != nullptr) { + if (cn->val == value) { + return true; + } + else if (cn->val > value) { + cn = cn->left; + } + else if (cn->val < value) { + cn = cn->right; + } + } + + return false; + } + + void insert(Node *n) { + if (this->contains(n->val)) { + delete n; + return; + } + + this->_insert_rec(this->root, n); + + this->_fix_tree(n); + + this->root = n; + while (RBTree::parent(this->root) != nullptr) { + root = RBTree::parent(root); + } + } + + void insert(int val) { + auto nn = new Node { + nullptr, nullptr, nullptr, BLACK, val + }; + + this->insert(nn); + } + + void merge(Node *n) { // l-n-r (in-order) traversal + if (n == nullptr) { + return; + } + + if (n->left != nullptr) { + this->merge(n->left); + } + + this->insert(n->val); + + if (n->right != nullptr) { + this->merge(n->right); + } + } + + void merge(RBTree &tree) { + this->merge(tree.root); + } + + void print_tree(const std::string& prefix) { + printf("digraph %s {\n", prefix.c_str()); + this->_print_tree(this->root); + printf("}\n"); + } +}; + +class AVLTree { +public: + struct Node { + Node *left = nullptr; + Node *right = nullptr; + + int val = -1; + int height = 1; + }; + + enum balance_type { + LEFT_SKEWD = -1, + BALANCED = 0, + RIGHT_SKEWD = 1 + }; + +private: + Node *root; + + static int height(Node *n) { + if (n == nullptr) { + return 0; + } + + return n->height; + } + + static balance_type balance(Node *n) { + if (n == nullptr) { + return balance_type::BALANCED; + } + + int diff = AVLTree::height(n->left) - AVLTree::height(n->right); + return diff == 2? balance_type::LEFT_SKEWD : (diff == -2? balance_type::RIGHT_SKEWD : balance_type::BALANCED); + }; + + static Node* small_left_rotation(Node *n) { + Node *rst = n->right; + Node *lrst = rst->left; + + // Perform rotation + rst->left = n; + n->right = lrst; + + // Update heights + n->height = std::max(AVLTree::height(n->left), AVLTree::height(n->right)) + 1; + rst->height = std::max(AVLTree::height(rst->left), AVLTree::height(rst->right)) + 1; + + // Return new root + return rst; + } + + static Node* small_right_rotation(Node *n) { + Node *lst = n->left; + Node *rlst = lst->right; + + // Perform rotation + lst->right = n; + n->left = rlst; + + // Update heights + n->height = std::max(AVLTree::height(n->left), AVLTree::height(n->right)) + 1; + lst->height = std::max(AVLTree::height(lst->left), AVLTree::height(lst->right)) + 1; + + // Return new root + return lst; + } + + Node* _internal_insert(Node *sub_root, Node *n) { + if (sub_root == nullptr) { + return n; + } + + if (sub_root->val > n->val) { + sub_root->left = this->_internal_insert(sub_root->left, n); + } + else { + sub_root->right = this->_internal_insert(sub_root->right, n); + } + + sub_root->height = std::max(AVLTree::height(sub_root->left), AVLTree::height(sub_root->right)) + 1; + + balance_type nb = AVLTree::balance(sub_root); + + if (nb == balance_type::LEFT_SKEWD) { + if (n->val < sub_root->left->val) { // l-l + return AVLTree::small_right_rotation(sub_root); + } + else if (n->val > sub_root->left->val) { // l-r + sub_root->left = AVLTree::small_left_rotation(sub_root->left); + return AVLTree::small_right_rotation(sub_root); + } + } + else if (nb == balance_type::RIGHT_SKEWD) { + if (n->val > sub_root->right->val) { // r-r + return AVLTree::small_left_rotation(sub_root); + } + else if (n->val < sub_root->right->val) { // r-l + sub_root->right = AVLTree::small_right_rotation(sub_root->right); + return AVLTree::small_left_rotation(sub_root); + } + } + + return sub_root; + } + + void _print_tree(Node *n) { + if (n == nullptr) { + return; + } + + printf(" %d\n", n->val); + + if (n->left != nullptr) { + printf(" %d -> %d\n", n->val, n->left->val); + this->_print_tree(n->left); + } + + if (n->right != nullptr) { + printf(" %d -> %d\n", n->val, n->right->val); + this->_print_tree(n->right); + } + } + +public: + bool contains(int value) { + auto cn = this->root; + + while (cn != nullptr) { + if (cn->val == value) { + return true; + } + else if (cn->val > value) { + cn = cn->left; + } + else if (cn->val < value) { + cn = cn->right; + } + } + + return false; + } + + void insert(Node *node) { + if (this->contains(node->val)) { + delete node; + return; + } + + this->root = AVLTree::_internal_insert(this->root, node); + } + + void insert(int val) { + auto nn = new Node { + nullptr, nullptr, val, 1 + }; + + this->insert(nn); + } + + void merge(Node *n) { // l-n-r (in-order) traversal + if (n == nullptr) { + return; + } + + if (n->left != nullptr) { + this->merge(n->left); + } + + this->insert(n->val); + + if (n->right != nullptr) { + this->merge(n->right); + } + } + + void merge(AVLTree &tree) { + this->merge(tree.root); + } + + void print_tree(const std::string& prefix) { + printf("digraph %s {\n", prefix.c_str()); + this->_print_tree(this->root); + printf("}\n"); + } +}; + +#define DATASET 5 + +int main() { +#if DATASET == 1 + auto ftv = {5, 32, 8, 4, 21}; + auto stv = {14, 48, 88, 13, 33, 37}; +#elif DATASET == 2 + auto ftv = {9123, 4409, 8243, 3504, 5432, 8943}; + auto stv = {4686, 232, 8780, 7792, 248, 632, 4122}; +#elif DATASET == 3 + auto ftv = {9,8,7,6}; + auto stv = {1,2,3,4,5,6,7}; +#else + auto ftv = {1,2,3,4,5,6,7}; + auto stv = {8,9,10,11,12,13,14,15}; +#endif + RBTree rbt1{}; + RBTree rbt2{}; + RBTree rbt3{}; + AVLTree avlt1{}; + AVLTree avlt2{}; + AVLTree avlt3{}; + + { + printf("==========RED-BLACK TREE SECTION==========\n"); + printf("==========1. INSERTION====================\n"); + double et1, et2 = et1 = 0; + { + auto start = std::chrono::high_resolution_clock::now(); + for (int d : ftv) { + rbt1.insert(d); + } + time_passed(start, et1); + } + { + auto start = std::chrono::high_resolution_clock::now(); + for (int d : stv) { + rbt2.insert(d); + } + time_passed(start, et2); + } + printf("%.0f %.0f\n", et1, et2); + printf("==========2. MERGING======================\n"); + double et = 0; + { + auto start = std::chrono::high_resolution_clock::now(); + rbt3.merge(rbt1); + rbt3.merge(rbt2); + time_passed(start, et); + } + printf("%.0f\n", et); + printf("===================END====================\n"); + } + + printf("\n\n"); + + { + printf("==========AVL TREE SECTION================\n"); + printf("==========1. INSERTION====================\n"); + double et1, et2 = et1 = 0; + { + auto start = std::chrono::high_resolution_clock::now(); + for (int d : ftv) { + avlt1.insert(d); + } + time_passed(start, et1); + } + { + auto start = std::chrono::high_resolution_clock::now(); + for (int d : stv) { + avlt2.insert(d); + } + time_passed(start, et2); + } + printf("%.0f %.0f\n", et1, et2); + printf("==========2. MERGING======================\n"); + double et = 0; + { + auto start = std::chrono::high_resolution_clock::now(); + avlt3.merge(avlt1); + avlt3.merge(avlt2); + time_passed(start, et); + } + printf("%.0f\n", et); + printf("===================END====================\n"); + } + + printf("==========PRINTING TREES==================\n"); + // all output done in dot-graph-notation + rbt3.print_tree("rb3"); + avlt3.print_tree("avl3"); + printf("==========END PRINTING TREES==============\n"); + + + return 0; +} diff --git a/3sem/data structures and algos/06/аисд отчёт прак 6.pdf b/3sem/data structures and algos/06/аисд отчёт прак 6.pdf new file mode 100644 index 0000000..dda72fb Binary files /dev/null and b/3sem/data structures and algos/06/аисд отчёт прак 6.pdf differ