From 68cefa440f2ee221616911cfc29a5c3b78939c4a Mon Sep 17 00:00:00 2001 From: Dmitriy Gorshenin Date: Sat, 14 May 2022 15:23:20 +0300 Subject: [PATCH] =?UTF-8?q?4=20=D1=81=D0=B5=D0=BC=D0=B5=D1=81=D1=82=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Part2/3Lab/3Lab.cpp | 514 +++++++++++++++++++++++++++++++++++++++++++ Part2/3Lab/README.md | 23 ++ 2 files changed, 537 insertions(+) create mode 100644 Part2/3Lab/3Lab.cpp create mode 100644 Part2/3Lab/README.md diff --git a/Part2/3Lab/3Lab.cpp b/Part2/3Lab/3Lab.cpp new file mode 100644 index 0000000..7215592 --- /dev/null +++ b/Part2/3Lab/3Lab.cpp @@ -0,0 +1,514 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +struct Node { + int key, h; + Node* L[2]; + Node(int k) : key(k), h(1) { L[0] = L[1] = nullptr; } + ~Node() { delete L[1]; delete L[0]; } + void Display(int, int, int); + Node(const Node&) = delete; + Node& operator = (const Node&) = delete; + + friend int height(Node*& p) + { + return p ? p->h : 0; + } + int balancefactor() + { + return height(L[1]) - height(L[0]); + } + + int fixheight() + { + auto hl = height(L[0]); + auto hr = height(L[1]); + h = (hl > hr ? hl : hr) + 1; + return h; + } + + + // friend class Tree; +}; + +using MyStack = stack>; + +struct myiter : public iterator +{ + Node* Ptr; + MyStack St; + myiter(Node* p = nullptr) : Ptr(p) {} + myiter(Node* p, const MyStack&& St) : Ptr(p), St(move(St)) {} + bool operator == (const myiter& Other) const { return Ptr == Other.Ptr; } + bool operator != (const myiter& Other) const { return !(*this == Other); } + myiter& operator++(); + myiter operator++(int) { myiter temp(*this); ++* this; return temp; } + pointer operator->() { return &Ptr->key; } + reference operator*() { return Ptr->key; } +}; + +template +class outiter : public iterator +{ +protected: + Container& container; + Iter iter; +public: + explicit outiter(Container& c, Iter it) : container(c), iter(it) { } + const outiter& + operator = (const typename Container::value_type& value) { + iter = container.insert(value, iter).first; + return *this; + } + const outiter& + operator = (const outiter&) { return *this; } + outiter& operator* () { return *this; } + outiter& operator++ () { return *this; } + outiter& operator++ (int) { return *this; } +}; + +template +inline outiter outinserter(Container& c, Iter it) +{ + return outiter(c, it); +} + +class Tree { + static size_t tags; + char tag; + Node* root; + size_t n; +public: + using key_type = int; + using value_type = int; + using key_compare = less; + void swap(Tree& rgt) + { + using std::swap; + swap(tag, rgt.tag); + swap(root, rgt.root); + swap(n, rgt.n); + } + static int Count; + myiter Insert(const int& k, myiter where) { + return insert(k, where).first; + } + size_t H() { return (root ? root->h : 0); } + void Display(int = 1); + myiter begin()const; + myiter end()const { return myiter(nullptr); } + void clear() { n = 0; delete root; root = nullptr; } + pair insert(int, myiter = myiter(nullptr)); + Tree() : tag(static_cast('A' + tags++)), root(nullptr), n(0) { } + Tree(int N) : tag(static_cast('A' + tags++)), root(nullptr), n(0) { + clear(); + Count = 0; + for (int i = 0; i < N; ++i) { + int num = rand() % 16; + Tree::Count += insert(num).second; + } + } + int size() { return n; } + ~Tree() { delete root; } + myiter find(int)const; + Tree(const Tree& rgt) : Tree() { + for (auto x = rgt.begin(); x != rgt.end(); ++x) insert(*x); + } + Tree(Tree&& rgt) : Tree() { swap(rgt); } + template + Tree(MyIt first, MyIt last) : Tree() { + for (; first != last; ++first) insert(*first); + } + Tree(list data) : Tree() { + for (auto x = data.begin(); x != data.end(); ++x) { + insert(*x); + } + } + Tree& operator=(const Tree& rgt) + { + Tree temp; + for (auto x : rgt) temp.insert(x); + swap(temp); + return *this; + } + Tree& operator=(Tree&& rgt) + { + swap(rgt); return *this; + } + Tree& operator |= (const Tree&); + Tree operator | (const Tree& rgt) const + { + Tree result(*this); return (result |= rgt); + } + Tree& operator &= (const Tree&); + Tree operator & (const Tree& rgt) const + { + Tree result(*this); return (result &= rgt); + } + Tree& operator -= (const Tree&); + Tree operator - (const Tree& rgt) const + { + Tree result(*this); return (result -= rgt); + } + Tree& operator ^= (const Tree&); + Tree operator ^ (const Tree& rgt) const + { + Tree result(*this); return (result ^= rgt); + } + void showme() { + cout << tag << ": { "; + + if (root) { + cout << root->key << ' '; + outnode(root); + } + + cout << '}' << endl; + } + void outnode(Node* root) { + if (root->L[0]) { + cout << root->L[0]->key << ' '; + outnode(root->L[0]); + } + if (root->L[1]) { + cout << root->L[1]->key << ' '; + outnode(root->L[1]); + } + } + void Merge(Tree last, Tree& res) { + res.clear(); + merge(begin(), end(), last.begin(), last.end(), outinserter(res, myiter(nullptr))); + } + void subst(int p, Tree last, Tree& res) { + res.clear(); + auto qt = begin(); + int i = 0; + + while (i < p && qt != end()) { + res.insert(*qt); + ++qt; + ++i; + } + for (auto st = last.begin(); st != last.end(); ++st) { + res.insert(*st); + } + for (auto st = qt; st != end(); ++st) { + res.insert(*st); + } + } + void change(int p, Tree last, Tree& res) { + res.clear(); + auto qt = begin(); + int i = 0; + + while (i < p && qt != end()) { + res.insert(*qt); + ++qt; + ++i; + } + + for (auto st = last.begin(); st != last.end(); ++st) { + res.insert(*st); + ++qt; + } + + for (auto st = qt; st != end(); ++st) { + res.insert(*st); + } + } +}; + +int Tree::Count; + +myiter Tree::begin()const { + MyStack St; + Node* p(root); + if (p) { + while (p->L[0]) { + St.push(make_pair(p, 0)); + p = p->L[0]; + } + } + return myiter(p, move(St)); +} + +myiter& myiter::operator++() +{ + if (!Ptr) { + return *this; + } + if (Ptr->L[1]) { + St.push(make_pair(Ptr, 1)); + Ptr = Ptr->L[1]; + while (Ptr->L[0]) { + St.push(make_pair(Ptr, 0)); + Ptr = Ptr->L[0]; + } + } + else { + pair pp(Ptr, 1); + while (!St.empty() && pp.second) { pp = St.top(); St.pop(); } + if (pp.second) { + Ptr = nullptr; + } + else Ptr = pp.first; + } + return (*this); +} + +const int FIRSTROW = 0, +FIRSTCOL = 60, +MAXCOL = 120, +OFFSET[] = { 60, 23, 12, 6, 3, 2, 1 }, +MAXROW = FIRSTROW + 9, +MAXOUT = FIRSTROW + 6, +SHIFT = 2; +string SCREEN[MAXROW]; + +void clrscr(int f = 1) +{ + for (auto i = 0; i < MAXROW; ++i) { + + SCREEN[i] = ""; + SCREEN[i].resize(MAXCOL + 20, '.'); + } + if (f) system("cls"); +} + +void showscr() +{ + for (auto i = 0; i < MAXROW; ++i) { + SCREEN[i].resize(MAXCOL, '.'); + cout << SCREEN[i] << '\n'; + } +} + +int setval(string& s, int pos, int val) { + string t(to_string(val)); + for (auto p : t) s[pos++] = p; + return t.size(); +} + +void Tree::Display(int first) +{ + clrscr(first); + SCREEN[0] = "BSTh (H=" + to_string(H()) + " n=" + to_string(n) + ") --------->"; + if (root) { + SCREEN[0].resize(MAXCOL, '.'); + root->Display(0, FIRSTCOL, 1); + } + else SCREEN[0] += ""; + showscr(); +} + +void Node::Display(int row, int col, int depth) +{ + if ((row > MAXROW) || (col < 0) || (col > MAXCOL)) return; + if (row > MAXOUT) { + SCREEN[row].replace(col, 3, "+++"); + return; + } + + try { + setval(SCREEN[row], col, key); + setval(SCREEN[row + 1], col, h); + } + catch (exception& e) { + cout << e.what() << key << ' ' << row << ' ' << col << endl; + cin.get(); + } + catch (...) { cout << "Unknown error\n"; cin.get(); } + + if (L[0]) L[0]->Display(row + 1, col - OFFSET[depth], depth + 1); + if (L[1]) L[1]->Display(row + 1, col + OFFSET[depth], depth + 1); +} +myiter Tree::find(int k)const +{ + Node* p(root); + while (p && p->key != k) p = p->L[p->key > k]; + return myiter(p); +} + +pair Tree::insert(int k, myiter where) +{ + Node* p(root), * q(nullptr); + int a{ 0 }; + MyStack St; + //===== Инициализация ===== + if (!where.Ptr) { + if (!root) { + root = new Node(k); + n = 1; + return make_pair(myiter(root, move(St)), true); + } + } + else { + p = where.Ptr; + St = move(where.St); + } + + //===== Поиск места вставки ===== // + while (p) { + a = k > p->key ? 1 : 0; + St.push(make_pair(p, a)); + q = p->L[a]; + if (q) { + p = q; + } + else { + p->L[a] = q = new Node(k); + ++n; + break; + } + } + + int b_old{ 0 }; + while (!St.empty()) + { + auto pa = St.top(); St.pop(); + p = pa.first; a = pa.second; + int b(p->balancefactor()); + if (b) { + if ((b == 2) || (b == -2)) + { + --p->h; + b /= 2; + if (b == b_old) { + p->L[a] = q->L[1 - a]; + q->L[1 - a] = p; + if (p == root)p = root = q; + else St.top().first->L[St.top().second] = p = q; + p->fixheight(); + break; + } + else { + Node* r(q->L[1 - a]); + p->L[a] = r->L[1 - a]; + q->L[1 - a] = r->L[a]; + r->L[1 - a] = p; + r->L[a] = q; + + if (p == root) p = root = r; + else St.top().first->L[St.top().second] = p = r; + p->fixheight(); + break; + } + } + b_old = b; + p->fixheight(); + q = p; + } + else break; + } + return make_pair(myiter(p, move(St)), true); +} + +Tree& Tree::operator |= (const Tree& rgt) { + Tree temp; + set_union(begin(), end(), rgt.begin(), rgt.end(), outinserter(temp, myiter(nullptr))); + swap(temp); + return *this; +} + +Tree& Tree::operator &= (const Tree& rgt) { + Tree temp; + set_intersection(begin(), end(), rgt.begin(), rgt.end(), outinserter(temp, myiter(nullptr))); + swap(temp); + return *this; +} + +Tree& Tree::operator -= (const Tree& rgt) { + Tree temp; + set_difference(begin(), end(), rgt.begin(), rgt.end(), outinserter(temp, myiter(nullptr))); + swap(temp); + return *this; +} +Tree& Tree::operator ^= (const Tree& rgt) { + Tree temp; + set_symmetric_difference(begin(), end(), rgt.begin(), rgt.end(), outinserter(temp, myiter(nullptr))); + swap(temp); + return *this; +} +size_t Tree::tags = 0; + +using namespace std; + +int main() +{ + setlocale(LC_ALL, "Russian"); + system("chcp 1251"); + srand(time(nullptr)); + + int N = 16; + Tree home(rand()%N+1), + second(rand()%N+1), + third(rand()%N+1), + fourth(rand()%N+1), + fifth(rand()%N+1), + res1, res2, res3, res; + + home.Display(); + cout << "\nSequence in the form of a tree (further will be in the form of a sequence) ... "; + home.showme(); + cin.get(); + system("cls"); + + + + home.showme(); + second.showme(); + third.showme(); + fourth.showme(); + fifth.showme(); cout << endl; + + res1 = home | second; + cout << "A | B = "; res1.showme(); + res2 = third | fourth; + cout << "C | D = "; res2.showme(); + res3 = res1 - res2; + cout << "(A | B) - (C | D) = "; res3.showme(); + res = res3 ^ fifth; + cout << "(A | B) - (C | D) ^ E = "; res.showme(); + + cout << "\nGraphical representation in progress... "; + cin.get(); + res.Display(); + cout << "Result: "; res.showme(); + cin.get(); + + list test = {6, 7, 9, 2, 3}; + Tree merge_tree(test), resx; + home.Merge(merge_tree, resx); + resx.Display(); + cout << "Operation Merge\n"; + resx.showme(); + cin.get(); + + Tree subst_tree({3, 4, 0}), res4; + home.subst(2, subst_tree, res4); + res4.Display(); + cout << "Operation Subst\n"; + res4.showme(); + cin.get(); + + Tree change_tree({2, 8, 7}), res5; + home.change(3, change_tree, res5); + res5.Display(); + cout << "Operation Change\n"; + res5.showme(); + + cout << "\n ==== The end ====\n"; + cin.get(); + return 0; +} diff --git a/Part2/3Lab/README.md b/Part2/3Lab/README.md new file mode 100644 index 0000000..3c3894b --- /dev/null +++ b/Part2/3Lab/README.md @@ -0,0 +1,23 @@ +# AiSD +## Тема: Комбинированные структуры данных и стандартная библиотека шаблонов +##### Вариант 35 + + +### Цель работы +Получение практических знаний по созданию собственного контейнера для работы с множествами и последовательностями +### Задание +Реализовать индивидуальное задание темы «Множества + последовательности» в виде программы, используя свой контейнер для дерева двоичного поиска с хранением высоты дерева в каждом узле и доработать его для поддержки операций с последовательностями. +#### 1. Описание созданного контейнера +Для реализации поставленной задачи было решено использовать контейнер Container, на который ссылаются итераторы разного типа: он используется для хранения элементов множества. В основе реализации этого контейнера лежит дерево двоичного поиска, что обеспечивает оптимальное время выполнения операций: поиск, вставка, удаление за O(log n), где n – мощность множества +Но при всех плюсах есть существенный недостаток – при работе с элементами множества теряется информация о порядке добавления элемента и возможных повторах элементов +Для генерации множества используется генератор псевдослучайных чисел, из-за чего элементы множества могут повторяться. Также для генерации дерева была использована автобалансировка, поэтому элементы располагаются в том порядке, в котором они были разложены при автобалансировке, поэтому порядок элементов отличается от теоретического +Использованы две функции вывода дерева: та, которая выводит их в том порядке, в каком они были заложены в контейнер, и та, которая выводит значения узлов дерева, переходя от родителей к сыновьям + +#### 2. Реализованные функции для операций над последовательностями +Т.к. в библиотеки algorithm отсутствуют операции CHANGE и SUBST, они были реализованы самостоятельно +Функция subst вставляет последовательность B в последовательность А в заданное место. Сложность реализованной функции O(n log n) +Функция change заменяет последовательность элементами второй последовательности, начиная с позиции p. Сложность реализованной функции O(n) + +### Вывод +Стандартные контейнеры подходят для работы с множествами, однако для работы с последовательностями, где важен порядок добавления элементов в множество, стандартные контейнеры нужно дорабатывать. +В результате выполнения лабораторной работы был создан пользовательский контейнер на основе деревьев двоичного поиска \ No newline at end of file