From 79c99613883efb9d19c77c6820af0a5e80745974 Mon Sep 17 00:00:00 2001 From: GRayHook Date: Fri, 1 Aug 2025 19:40:48 +0700 Subject: [PATCH] =?UTF-8?q?qosd:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=B8=D1=82=D0=B5=D1=80=D0=B0=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D1=8B=20=D0=BF=D0=BE=20=D1=83=D0=B7=D0=BB=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/ifaces/IIterator.h | 14 +++++++++ include/ifaces/ILinkMixin.h | 1 + include/iterators/BFSIterator.h | 40 +++++++++++++++++++++++++ include/iterators/BaseIterator.h | 42 +++++++++++++++++++++++++++ include/iterators/DFSIterator.h | 43 +++++++++++++++++++++++++++ include/iterators/Traversal.h | 27 +++++++++++++++++ include/mixins/BaseLinkMixin.h | 7 +++++ src/main.cpp | 50 ++++++++++++++++++++++---------- 8 files changed, 208 insertions(+), 16 deletions(-) create mode 100644 include/ifaces/IIterator.h create mode 100644 include/iterators/BFSIterator.h create mode 100644 include/iterators/BaseIterator.h create mode 100644 include/iterators/DFSIterator.h create mode 100644 include/iterators/Traversal.h diff --git a/include/ifaces/IIterator.h b/include/ifaces/IIterator.h new file mode 100644 index 0000000..473a69a --- /dev/null +++ b/include/ifaces/IIterator.h @@ -0,0 +1,14 @@ +#pragma once + +/// \brief Интерфейс для классов-итераторов. +/// \tparam T Тип итерируемого элемента. +template +class IIterator { +public: + virtual T* operator->() const = 0; + virtual operator const T*() const = 0; + + virtual bool operator!=(const IIterator& other) const = 0; + + virtual IIterator& operator++() = 0; +}; diff --git a/include/ifaces/ILinkMixin.h b/include/ifaces/ILinkMixin.h index 67f3b6c..db07e52 100644 --- a/include/ifaces/ILinkMixin.h +++ b/include/ifaces/ILinkMixin.h @@ -14,5 +14,6 @@ public: virtual void linkChild(const ElemPtr& child) = 0; virtual void unlinkParent() = 0; virtual const std::vector& children() = 0; + virtual ElemPtr parent() = 0; virtual LinkPtr getLink() = 0; }; diff --git a/include/iterators/BFSIterator.h b/include/iterators/BFSIterator.h new file mode 100644 index 0000000..6c09596 --- /dev/null +++ b/include/iterators/BFSIterator.h @@ -0,0 +1,40 @@ +#pragma once +#include + +#include "iterators/BaseIterator.h" + +template +class BFSIterator : public BaseIterator { +public: + explicit BFSIterator(T* ptr) : BaseIterator(ptr) { + if (!this->current()) + return; + + for (auto& it : this->current()->children()) + q.push({it.get(), 1}); + } + + IIterator& operator++() override { + advance(); + return *this; + } + +protected: + std::queue> q; + + void advance() { + if (q.empty()) { + this->set_current(nullptr); + return; + } + + auto& [node, lvl] = q.front(); + q.pop(); + + this->set_current(node); + this->set_level(lvl); + + for (auto& it : this->current()->children()) + q.push({it.get(), lvl + 1}); + } +}; diff --git a/include/iterators/BaseIterator.h b/include/iterators/BaseIterator.h new file mode 100644 index 0000000..8173c1b --- /dev/null +++ b/include/iterators/BaseIterator.h @@ -0,0 +1,42 @@ +#pragma once + +#include "ifaces/IIterator.h" + +/// \brief Базовый итератор. +/// \tparam T Тип итерируемого элемента. +/// Предоставляет базовую реализацию методов для работы с итерируемыми объектами. +/// Возвращает объект-прокси, мимикрирующий под итерируемый элемент. Позволяет использовать +/// распаковку структуры для получения уровня элемента в поддереве. +template +class BaseIterator : public IIterator { +public: + explicit BaseIterator(T* ptr) : proxy{ptr, 0} {} + + struct Proxy { + T* e; + size_t level; + + T& operator*() const { return *e; } + T* operator->() const { return e; } + }; + Proxy& operator*() { return proxy; } + + T* operator->() const override { return current(); } + operator const T*() const { return current(); } + operator T&() const { return *current(); } + operator T*() const { return current(); } + + bool operator!=(const IIterator& other) const override { + const T* other_current = other; + return current() != other_current; + } + +protected: + T* current() const { return proxy.e; } + void set_current(T* e) { proxy.e = e; } + + size_t level() const { return proxy.level; } + void set_level(size_t level) { proxy.level = level; } +private: + Proxy proxy; +}; diff --git a/include/iterators/DFSIterator.h b/include/iterators/DFSIterator.h new file mode 100644 index 0000000..0d863cd --- /dev/null +++ b/include/iterators/DFSIterator.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include + +#include "iterators/BaseIterator.h" + +template +class DFSIterator : public BaseIterator { +public: + explicit DFSIterator(T* ptr) : BaseIterator(ptr) { + if (!this->current()) + return; + + for (auto it = this->current()->children().rbegin(); + it != this->current()->children().rend(); ++it) + s.push({it->get(), 1}); + } + + IIterator& operator++() override { + advance(); + return *this; + } + +protected: + std::stack> s; + + void advance() { + if (s.empty()) { + this->set_current(nullptr); + return; + } + + auto [node, lvl] = s.top(); + s.pop(); + + this->set_current(node); + this->set_level(lvl); + + for (auto it = this->current()->children().rbegin(); + it != this->current()->children().rend(); ++it) + s.push({it->get(), lvl + 1}); + } +}; diff --git a/include/iterators/Traversal.h b/include/iterators/Traversal.h new file mode 100644 index 0000000..38901c0 --- /dev/null +++ b/include/iterators/Traversal.h @@ -0,0 +1,27 @@ +#pragma once + +#include "ifaces/INode.h" + +#include "iterators/DFSIterator.h" +#include "iterators/BFSIterator.h" + +namespace traversal { + /// \brief Фабрика итераторов узлов дерева. + /// \tparam T Тип алгоритма для обхода дерева. + /// Конструирует итерируемый объект с заданным алгоритмом обхода. Например, в ширину + /// или глубину. + template + class Traversal { + INode* start; + + public: + explicit Traversal(INode* start) : start(start) {} + explicit Traversal(NodePtr start) : start(start.get()) {} + + Policy begin() const { return Policy(start); } + Policy end() const { return Policy(nullptr); } + }; + + using DFS = Traversal>; + using BFS = Traversal>; +} diff --git a/include/mixins/BaseLinkMixin.h b/include/mixins/BaseLinkMixin.h index 67ba4f6..8abc174 100644 --- a/include/mixins/BaseLinkMixin.h +++ b/include/mixins/BaseLinkMixin.h @@ -37,6 +37,13 @@ public: getLink()->setParent(nullptr); } + ElemPtr parent() override { + auto link = getLink(); + + ElemPtr parent = link->getParent(); + + return parent; + } const std::vector& children() override { auto link = getLink(); diff --git a/src/main.cpp b/src/main.cpp index 78b46eb..b8c12ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,19 +1,29 @@ -#include "nodes/SimpleNode.h" -#include "nodes/ComplexNode.h" #include + #include "Logger.h" -void printTree(const NodePtr& node, int indent = 0) { - if (!node) { - Logger::get("MAIN").err("No node"); - return; - } +#include "nodes/SimpleNode.h" +#include "nodes/ComplexNode.h" +#include "iterators/Traversal.h" - for (int i = 0; i < indent; ++i) std::cout << " "; - std::cout << node->name() << "\n"; - for (const auto& child : node->children()) - printTree(child, indent + 1); +void printNode(INode& node, size_t level) { + for (size_t i = level; i > 0; i--) + std::cout << " "; + std::cout << node.name() << "\n"; +} + +void printTreeBFS(INode& node) { + for (auto& child : traversal::BFS(&node)) + printNode(*child, 0); +} +void printTreeList(INode& node) { + for (auto& child : traversal::DFS(&node)) + printNode(*child, 0); +} +void printTreeLadder(INode& node) { + for (auto& [child, level] : traversal::DFS(&node)) + printNode(*child, level); } int main() { @@ -31,7 +41,7 @@ int main() { root->linkChild(child1); std::cout << "\nInit tree:\n"; - printTree(root); + printTreeLadder(*root); std::cout << "\n"; { @@ -83,21 +93,29 @@ int main() { } std::cout << "\nAnother tree:\n"; - printTree(root); + printTreeLadder(*root); + std::cout << "\n"; + + std::cout << "\nList:\n"; + printTreeList(*root); + std::cout << "\n"; + + std::cout << "\nBFS:\n"; + printTreeBFS(*root); std::cout << "\n"; logger.info("Unlinking ComplexChild2...\n"); child2->unlinkParent(); std::cout << "\nTree after unlink:\n"; - printTree(root); + printTreeLadder(*root); std::cout << "\n"; logger.info("Put refs of ComplexChild2, ComplexChild3 and its children"); } std::cout << "\nTree after scope out:\n"; - printTree(root); + printTreeLadder(*root); std::cout << "\n"; logger.info("Unlinking ComplexChild1 and ComplexChild3...\n"); @@ -114,7 +132,7 @@ int main() { root->linkChild(child4); std::cout << "\nTree flush and link SimpleChild4:\n"; - printTree(root); + printTreeLadder(*root); std::cout << "\n"; }