From f0bd3c8862c2c57176a3c5253a16f8d40fad6468 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sat, 21 Sep 2024 19:56:58 +0000 Subject: [PATCH 01/42] Add graph class in utils --- lib/src/util.cpp | 24 ++++++++++++++++++++++++ lib/src/util.hpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/lib/src/util.cpp b/lib/src/util.cpp index 81e15bd..b3dbb17 100644 --- a/lib/src/util.cpp +++ b/lib/src/util.cpp @@ -1 +1,25 @@ #include "util.hpp" + +#include + +template +void Graph::addVertex(const T &data) { + vertices.push_back(std::make_shared>(data)); +} + +template +void Graph::addEdge(std::shared_ptr> source, + std::shared_ptr> reciever) { + source->adjacent.push_back(reciever); +} + +template +void Graph::printGraph() const { + for (const auto &vertex : vertices) { + std::cout << vertex->data << " -> "; + for (const auto &neighbor : vertex->adjacent) { + std::cout << neighbor->data << " "; + } + std::cout << std::endl; + } +} \ No newline at end of file diff --git a/lib/src/util.hpp b/lib/src/util.hpp index e69de29..f9ad27f 100644 --- a/lib/src/util.hpp +++ b/lib/src/util.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include + +/// @brief Graphs vertex +/// @tparam T +template +struct Vertex { + T data; + std::list>> adjacent; + + Vertex(const T &d) : data(d) {} +}; + +/// @brief Basic graph +/// @tparam T +template +class Graph { + public: + /** + * @brief + * Add a new vertex to the graph + * @param data + */ + void addVertex(const T &data); + + /** + * @brief + * Add an edge between two vertices + * @param source + * @param reciever + */ + void addEdge(std::shared_ptr> source, + std::shared_ptr> reciever); + + /** + * @brief + * Print the adjacency list of the graph + */ + void printGraph() const; + + private: + std::vector>> vertices; +}; \ No newline at end of file From 1d846ff417f4d3ab7f548ff228a315197397f7cf Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sat, 21 Sep 2024 20:18:16 +0000 Subject: [PATCH 02/42] Undirected edge adding func --- lib/src/util.cpp | 15 +++++++++++---- lib/src/util.hpp | 19 ++++++++++++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/lib/src/util.cpp b/lib/src/util.cpp index b3dbb17..3052b15 100644 --- a/lib/src/util.cpp +++ b/lib/src/util.cpp @@ -3,18 +3,25 @@ #include template -void Graph::addVertex(const T &data) { +void Graph::AddVertex(const T &data) { vertices.push_back(std::make_shared>(data)); } template -void Graph::addEdge(std::shared_ptr> source, - std::shared_ptr> reciever) { +void Graph::AddDirEdge(std::shared_ptr> source, + std::shared_ptr> reciever) { source->adjacent.push_back(reciever); } template -void Graph::printGraph() const { +void Graph::AddEdge(std::shared_ptr> vertex_1, + std::shared_ptr> vertex_2) { + Graph::AddDirEdge(vertex_1, vertex_2); + Graph::AddDirEdge(vertex_2, vertex_1); +} + +template +void Graph::PrintGraph() const { for (const auto &vertex : vertices) { std::cout << vertex->data << " -> "; for (const auto &neighbor : vertex->adjacent) { diff --git a/lib/src/util.hpp b/lib/src/util.hpp index f9ad27f..e2541a6 100644 --- a/lib/src/util.hpp +++ b/lib/src/util.hpp @@ -24,22 +24,31 @@ class Graph { * Add a new vertex to the graph * @param data */ - void addVertex(const T &data); + void AddVertex(const T &data); /** * @brief - * Add an edge between two vertices + * Add a directed edge between two vertices * @param source * @param reciever */ - void addEdge(std::shared_ptr> source, - std::shared_ptr> reciever); + void AddDirEdge(std::shared_ptr> source, + std::shared_ptr> reciever); + + /** + * @brief + * Add a non-directed edge between two vertices + * @param source + * @param reciever + */ + void AddEdge(std::shared_ptr> vertex_1, + std::shared_ptr> vertex_2); /** * @brief * Print the adjacency list of the graph */ - void printGraph() const; + void PrintGraph() const; private: std::vector>> vertices; From d3602f6e09cc4070aaba2f4da0af687504e8c52d Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sat, 21 Sep 2024 20:20:12 +0000 Subject: [PATCH 03/42] Rename files --- lib/src/{util.cpp => graph.cpp} | 2 +- lib/src/{util.hpp => graph.hpp} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/src/{util.cpp => graph.cpp} (97%) rename lib/src/{util.hpp => graph.hpp} (100%) diff --git a/lib/src/util.cpp b/lib/src/graph.cpp similarity index 97% rename from lib/src/util.cpp rename to lib/src/graph.cpp index 3052b15..f6b586f 100644 --- a/lib/src/util.cpp +++ b/lib/src/graph.cpp @@ -1,4 +1,4 @@ -#include "util.hpp" +#include "graph.hpp" #include diff --git a/lib/src/util.hpp b/lib/src/graph.hpp similarity index 100% rename from lib/src/util.hpp rename to lib/src/graph.hpp From 22ffad770aae3fb1b8252fb74af41e9762f5af8e Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 09:08:21 +0000 Subject: [PATCH 04/42] Graph class improvement --- lib/src/graph.cpp | 43 +++++++++++++++++++++++++++++++++++++++---- lib/src/graph.hpp | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/lib/src/graph.cpp b/lib/src/graph.cpp index f6b586f..eb4598a 100644 --- a/lib/src/graph.cpp +++ b/lib/src/graph.cpp @@ -7,17 +7,52 @@ void Graph::AddVertex(const T &data) { vertices.push_back(std::make_shared>(data)); } +template +void Graph::DeleteVertex(std::shared_ptr> vertex) { + // Find the vertex in the graph + auto it = std::find(vertices.begin(), vertices.end(), vertex); + if (it == vertices.end()) { + // Vertex not found + return; + } + + // Remove the vertex from the graph + vertices.erase(it); + + // Remove edges pointing to the vertex + for (auto &v : vertices) { + v->adjacent.erase( + std::remove(v->adjacent.begin(), v->adjacent.end(), vertex), + v->adjacent.end()); + } +} + template void Graph::AddDirEdge(std::shared_ptr> source, - std::shared_ptr> reciever) { - source->adjacent.push_back(reciever); + std::shared_ptr> target) { + source->adjacent.push_back(target); +} + +template +void Graph::DeleteDirEdge(std::shared_ptr> source, + std::shared_ptr> target) { + source->adjacent.erase( + std::remove(source->adjacent.begin(), source->adjacent.end(), target), + source->adjacent.end()); } template void Graph::AddEdge(std::shared_ptr> vertex_1, std::shared_ptr> vertex_2) { - Graph::AddDirEdge(vertex_1, vertex_2); - Graph::AddDirEdge(vertex_2, vertex_1); + AddDirEdge(vertex_1, vertex_2); + AddDirEdge(vertex_2, vertex_1); +} + +template +void Graph::DeleteEdge(std::shared_ptr> vertex_1, + std::shared_ptr> vertex_2) { + DeleteDirEdge(vertex_1, vertex_2); + DeleteDirEdge(vertex_2, vertex_1); } template diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index e2541a6..19c3000 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -1,17 +1,17 @@ #pragma once -#include #include +#include #include /// @brief Graphs vertex /// @tparam T template struct Vertex { - T data; - std::list>> adjacent; - Vertex(const T &d) : data(d) {} + + T data; + std::set>> adjacent; }; /// @brief Basic graph @@ -26,24 +26,48 @@ class Graph { */ void AddVertex(const T &data); + /** + * @brief + * Delete a vertex from the graph + * @param vertex + */ + void DeleteVertex(std::shared_ptr> vertex); + /** * @brief * Add a directed edge between two vertices * @param source - * @param reciever + * @param target */ void AddDirEdge(std::shared_ptr> source, - std::shared_ptr> reciever); + std::shared_ptr> target); + /** + * @brief + * Delete a directed edge between two vertices + * @param source + * @param target + */ + void DeleteDirEdge(std::shared_ptr> source, + std::shared_ptr> target); /** * @brief * Add a non-directed edge between two vertices * @param source - * @param reciever + * @param target */ void AddEdge(std::shared_ptr> vertex_1, std::shared_ptr> vertex_2); + /** + * @brief + * Delete a non-directed edge between two vertices + * @param source + * @param target + */ + void DeleteEdge(std::shared_ptr> vertex_1, + std::shared_ptr> vertex_2); + /** * @brief * Print the adjacency list of the graph From 3709d1238c5239761dca9057b75d2599fb7b981f Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 10:57:45 +0000 Subject: [PATCH 05/42] Return utils files --- lib/src/utils.cpp | 1 + lib/src/utils.hpp | 0 2 files changed, 1 insertion(+) create mode 100644 lib/src/utils.cpp create mode 100644 lib/src/utils.hpp diff --git a/lib/src/utils.cpp b/lib/src/utils.cpp new file mode 100644 index 0000000..0c58fd6 --- /dev/null +++ b/lib/src/utils.cpp @@ -0,0 +1 @@ +#include "utils.hpp" \ No newline at end of file diff --git a/lib/src/utils.hpp b/lib/src/utils.hpp new file mode 100644 index 0000000..e69de29 From e3e497ce403bac5ec631fa5f2f0c6fefa1d93832 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 10:59:01 +0000 Subject: [PATCH 06/42] Move methods definitions to the header --- lib/src/graph.cpp | 67 ----------------------------------------------- lib/src/graph.hpp | 61 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 75 deletions(-) delete mode 100644 lib/src/graph.cpp diff --git a/lib/src/graph.cpp b/lib/src/graph.cpp deleted file mode 100644 index eb4598a..0000000 --- a/lib/src/graph.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "graph.hpp" - -#include - -template -void Graph::AddVertex(const T &data) { - vertices.push_back(std::make_shared>(data)); -} - -template -void Graph::DeleteVertex(std::shared_ptr> vertex) { - // Find the vertex in the graph - auto it = std::find(vertices.begin(), vertices.end(), vertex); - if (it == vertices.end()) { - // Vertex not found - return; - } - - // Remove the vertex from the graph - vertices.erase(it); - - // Remove edges pointing to the vertex - for (auto &v : vertices) { - v->adjacent.erase( - std::remove(v->adjacent.begin(), v->adjacent.end(), vertex), - v->adjacent.end()); - } -} - -template -void Graph::AddDirEdge(std::shared_ptr> source, - std::shared_ptr> target) { - source->adjacent.push_back(target); -} - -template -void Graph::DeleteDirEdge(std::shared_ptr> source, - std::shared_ptr> target) { - source->adjacent.erase( - std::remove(source->adjacent.begin(), source->adjacent.end(), target), - source->adjacent.end()); -} - -template -void Graph::AddEdge(std::shared_ptr> vertex_1, - std::shared_ptr> vertex_2) { - AddDirEdge(vertex_1, vertex_2); - AddDirEdge(vertex_2, vertex_1); -} - -template -void Graph::DeleteEdge(std::shared_ptr> vertex_1, - std::shared_ptr> vertex_2) { - DeleteDirEdge(vertex_1, vertex_2); - DeleteDirEdge(vertex_2, vertex_1); -} - -template -void Graph::PrintGraph() const { - for (const auto &vertex : vertices) { - std::cout << vertex->data << " -> "; - for (const auto &neighbor : vertex->adjacent) { - std::cout << neighbor->data << " "; - } - std::cout << std::endl; - } -} \ No newline at end of file diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 19c3000..985ca25 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -1,5 +1,7 @@ #pragma once +#include +#include #include #include #include @@ -24,14 +26,37 @@ class Graph { * Add a new vertex to the graph * @param data */ - void AddVertex(const T &data); + void AddVertex(const T &data) { + vertices.push_back(std::make_shared>(data)); + }; + + std::shared_ptr> operator[](size_t index) { + return vertices[index]; + } + const std::shared_ptr> operator[](size_t index) const { + return vertices[index]; + } /** * @brief * Delete a vertex from the graph * @param vertex */ - void DeleteVertex(std::shared_ptr> vertex); + void DeleteVertex(std::shared_ptr> vertex) { + // Find the vertex in the graph + auto it = std::find(vertices.begin(), vertices.end(), vertex); + if (it == vertices.end()) { + // Vertex not found + return; + } + + // Remove edges pointing to the vertex + for (auto &v : vertices[it - vertices.begin()]->adjacent) { + DeleteEdge(v, vertices[it - vertices.begin()]); + } + // Remove the vertex from the graph + vertices.erase(it); + } /** * @brief @@ -40,7 +65,9 @@ class Graph { * @param target */ void AddDirEdge(std::shared_ptr> source, - std::shared_ptr> target); + std::shared_ptr> target) { + source->adjacent.insert(target); + } /** * @brief @@ -49,7 +76,11 @@ class Graph { * @param target */ void DeleteDirEdge(std::shared_ptr> source, - std::shared_ptr> target); + std::shared_ptr> target) { + source->adjacent.erase( + std::find(source->adjacent.begin(), source->adjacent.end(), target)); + } + /** * @brief * Add a non-directed edge between two vertices @@ -57,7 +88,10 @@ class Graph { * @param target */ void AddEdge(std::shared_ptr> vertex_1, - std::shared_ptr> vertex_2); + std::shared_ptr> vertex_2) { + AddDirEdge(vertex_1, vertex_2); + AddDirEdge(vertex_2, vertex_1); + } /** * @brief @@ -66,14 +100,25 @@ class Graph { * @param target */ void DeleteEdge(std::shared_ptr> vertex_1, - std::shared_ptr> vertex_2); + std::shared_ptr> vertex_2) { + DeleteDirEdge(vertex_1, vertex_2); + DeleteDirEdge(vertex_2, vertex_1); + } /** * @brief * Print the adjacency list of the graph */ - void PrintGraph() const; + void PrintGraph() const { + for (const auto &vertex : vertices) { + std::cout << vertex->data << " -> "; + for (const auto &neighbor : vertex->adjacent) { + std::cout << neighbor->data << " "; + } + std::cout << std::endl; + } + } private: std::vector>> vertices; -}; \ No newline at end of file +}; From 75d57fac21972232c3f699e4cb5b096d0628852d Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 17:33:23 +0000 Subject: [PATCH 07/42] Improve naming --- lib/src/graph.hpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 985ca25..f73b126 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -27,14 +27,14 @@ class Graph { * @param data */ void AddVertex(const T &data) { - vertices.push_back(std::make_shared>(data)); + vertices_.push_back(std::make_shared>(data)); }; std::shared_ptr> operator[](size_t index) { - return vertices[index]; + return vertices_[index]; } const std::shared_ptr> operator[](size_t index) const { - return vertices[index]; + return vertices_[index]; } /** @@ -44,23 +44,23 @@ class Graph { */ void DeleteVertex(std::shared_ptr> vertex) { // Find the vertex in the graph - auto it = std::find(vertices.begin(), vertices.end(), vertex); - if (it == vertices.end()) { + auto it = std::find(vertices_.begin(), vertices_.end(), vertex); + if (it == vertices_.end()) { // Vertex not found return; } // Remove edges pointing to the vertex - for (auto &v : vertices[it - vertices.begin()]->adjacent) { - DeleteEdge(v, vertices[it - vertices.begin()]); + for (auto &v : vertices_[it - vertices_.begin()]->adjacent) { + DeleteEdge(v, vertices_[it - vertices_.begin()]); } // Remove the vertex from the graph - vertices.erase(it); + vertices_.erase(it); } /** * @brief - * Add a directed edge between two vertices + * Add a directed edge between two vertices_ * @param source * @param target */ @@ -71,19 +71,20 @@ class Graph { /** * @brief - * Delete a directed edge between two vertices + * Delete a directed edge between two vertices_ * @param source * @param target */ void DeleteDirEdge(std::shared_ptr> source, std::shared_ptr> target) { + // std::find(source->adjacent.begin(), source->adjacent.end(), target); source->adjacent.erase( - std::find(source->adjacent.begin(), source->adjacent.end(), target)); + *std::find(source->adjacent.begin(), source->adjacent.end(), target)); } /** * @brief - * Add a non-directed edge between two vertices + * Add a non-directed edge between two vertices_ * @param source * @param target */ @@ -95,7 +96,7 @@ class Graph { /** * @brief - * Delete a non-directed edge between two vertices + * Delete a non-directed edge between two vertices_ * @param source * @param target */ @@ -110,7 +111,7 @@ class Graph { * Print the adjacency list of the graph */ void PrintGraph() const { - for (const auto &vertex : vertices) { + for (const auto &vertex : vertices_) { std::cout << vertex->data << " -> "; for (const auto &neighbor : vertex->adjacent) { std::cout << neighbor->data << " "; @@ -120,5 +121,5 @@ class Graph { } private: - std::vector>> vertices; + std::vector>> vertices_; }; From 0c36f3e32d4dafa774abe50e40af8a8951be2420 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 17:35:06 +0000 Subject: [PATCH 08/42] Task_01 classes --- task_01/src/main.cpp | 24 ++++++++++++++++++++++-- task_01/src/packman.hpp | 21 +++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 task_01/src/packman.hpp diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp index 0e4393b..bd14c37 100644 --- a/task_01/src/main.cpp +++ b/task_01/src/main.cpp @@ -1,3 +1,23 @@ -#include +#include "packman.hpp" -int main() { return 0; } +int main() { + DependencyGraph dg_1; + + dg_1.AddVertex("Lib_1"); + dg_1.AddVertex("Lib_2"); + dg_1.AddVertex("Lib_3"); + dg_1.AddVertex("Lib_4"); + dg_1.AddVertex("Lib_5"); + + dg_1.AddDirEdge(dg_1[0], dg_1[1]); + dg_1.AddDirEdge(dg_1[1], dg_1[2]); + dg_1.AddDirEdge(dg_1[2], dg_1[3]); + dg_1.AddDirEdge(dg_1[4], dg_1[1]); + dg_1.AddDirEdge(dg_1[0], dg_1[3]); + + dg_1.PrintGraph(); + + dg_1.DeleteDirEdge(dg_1[0], dg_1[1]); + + dg_1.PrintGraph(); +} diff --git a/task_01/src/packman.hpp b/task_01/src/packman.hpp new file mode 100644 index 0000000..a526110 --- /dev/null +++ b/task_01/src/packman.hpp @@ -0,0 +1,21 @@ +#include + +#include "graph.hpp" + +struct Library : public Vertex { + Library(const std::string& name) : Vertex(name) {} +}; + +class DependencyGraph : public Graph {}; + +class PackageManager { + public: + PackageManager(std::shared_ptr dep_graph) + : dependencies{dep_graph} {} + + std::vector FindDownloadingOrder( + std::shared_ptr target); + + private: + std::shared_ptr dependencies; +}; \ No newline at end of file From 3fe4cd47f9e70ef07c7873ce2c7b5b087c1bd9eb Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 21:11:07 +0000 Subject: [PATCH 09/42] Improve methods naming --- lib/src/graph.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index f73b126..2224ce6 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -39,10 +39,10 @@ class Graph { /** * @brief - * Delete a vertex from the graph + * Remove a vertex from the graph * @param vertex */ - void DeleteVertex(std::shared_ptr> vertex) { + void RemoveVertex(std::shared_ptr> vertex) { // Find the vertex in the graph auto it = std::find(vertices_.begin(), vertices_.end(), vertex); if (it == vertices_.end()) { @@ -52,7 +52,7 @@ class Graph { // Remove edges pointing to the vertex for (auto &v : vertices_[it - vertices_.begin()]->adjacent) { - DeleteEdge(v, vertices_[it - vertices_.begin()]); + RemoveEdge(v, vertices_[it - vertices_.begin()]); } // Remove the vertex from the graph vertices_.erase(it); @@ -60,7 +60,7 @@ class Graph { /** * @brief - * Add a directed edge between two vertices_ + * Add a directed edge between two vertices * @param source * @param target */ @@ -71,11 +71,11 @@ class Graph { /** * @brief - * Delete a directed edge between two vertices_ + * Remove a directed edge between two vertices * @param source * @param target */ - void DeleteDirEdge(std::shared_ptr> source, + void RemoveDirEdge(std::shared_ptr> source, std::shared_ptr> target) { // std::find(source->adjacent.begin(), source->adjacent.end(), target); source->adjacent.erase( @@ -84,7 +84,7 @@ class Graph { /** * @brief - * Add a non-directed edge between two vertices_ + * Add a non-directed edge between two vertices * @param source * @param target */ @@ -96,14 +96,14 @@ class Graph { /** * @brief - * Delete a non-directed edge between two vertices_ + * Remove a non-directed edge between two vertices * @param source * @param target */ - void DeleteEdge(std::shared_ptr> vertex_1, + void RemoveEdge(std::shared_ptr> vertex_1, std::shared_ptr> vertex_2) { - DeleteDirEdge(vertex_1, vertex_2); - DeleteDirEdge(vertex_2, vertex_1); + RemoveDirEdge(vertex_1, vertex_2); + RemoveDirEdge(vertex_2, vertex_1); } /** From 22d90b8fe59099237132bd9f56e63b9096ff411e Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 21:11:32 +0000 Subject: [PATCH 10/42] Add Size() method --- lib/src/graph.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 2224ce6..e3233ae 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -58,6 +58,13 @@ class Graph { vertices_.erase(it); } + /** + * @brief + * Returns the number of vertices in the graph + * @return size_t + */ + size_t Size() { return vertices_.size(); } + /** * @brief * Add a directed edge between two vertices From e1ce917c133f4c8a9ee5e944acf37dad8f6c7101 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 22:32:12 +0000 Subject: [PATCH 11/42] Disacard changes --- lib/src/graph.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index e3233ae..1397090 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -37,6 +37,17 @@ class Graph { return vertices_[index]; } + /** + * @brief + * Find vertexes index + * @param vertex + * @return size_t + */ + size_t Find(const std::shared_ptr> &vertex) { + return std::find(vertices_.begin(), vertices_.end(), vertex) - + vertices_.begin(); + }; + /** * @brief * Remove a vertex from the graph From 310e284557b5ab9a12edf980c3dcee63ceafb7c6 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 23 Sep 2024 09:50:19 +0000 Subject: [PATCH 12/42] task_01 packman alogirthm --- task_01/src/main.cpp | 7 +++---- task_01/src/packman.cpp | 31 +++++++++++++++++++++++++++++++ task_01/src/packman.hpp | 26 ++++++++++++++++++-------- 3 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 task_01/src/packman.cpp diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp index bd14c37..2ed1511 100644 --- a/task_01/src/main.cpp +++ b/task_01/src/main.cpp @@ -15,9 +15,8 @@ int main() { dg_1.AddDirEdge(dg_1[4], dg_1[1]); dg_1.AddDirEdge(dg_1[0], dg_1[3]); - dg_1.PrintGraph(); + PackageManager packman_1(dg_1); - dg_1.DeleteDirEdge(dg_1[0], dg_1[1]); - - dg_1.PrintGraph(); + for (size_t j = 0; j < dg_1.Size(); ++j) + packman_1.FindDownloadingOrder(dg_1[j]); } diff --git a/task_01/src/packman.cpp b/task_01/src/packman.cpp new file mode 100644 index 0000000..36c3f44 --- /dev/null +++ b/task_01/src/packman.cpp @@ -0,0 +1,31 @@ +#include "packman.hpp" + +void PackageManager::FindingOrderStep( + std::shared_ptr> target) { + is_visited_[dependencies_.Find(target)] = true; + reverse_order_.push(target->data); + for (auto& neighbor : target->adjacent) { + if (!is_visited_[dependencies_.Find(neighbor)]) { + FindingOrderStep(neighbor); + } + } +} + +std::vector PackageManager::FindDownloadingOrder( + std::shared_ptr> target) { + is_visited_.resize(dependencies_.Size()); + for (size_t i = 0; i < is_visited_.size(); ++i) is_visited_[i] = false; + + FindingOrderStep(target); + + std::vector order; + + std::cout << "Downloading Order is:" << std::endl; + while (reverse_order_.size() > 0) { + order.push_back(reverse_order_.top()); + std::cout << reverse_order_.top() << " "; + reverse_order_.pop(); + } + std::cout << std::endl; + return order; +} \ No newline at end of file diff --git a/task_01/src/packman.hpp b/task_01/src/packman.hpp index a526110..87590ab 100644 --- a/task_01/src/packman.hpp +++ b/task_01/src/packman.hpp @@ -1,21 +1,31 @@ +#include #include #include "graph.hpp" -struct Library : public Vertex { - Library(const std::string& name) : Vertex(name) {} -}; - +/// @brief Graph of dependencies between libraries +/// The "parent" libraries should be installed before thier children class DependencyGraph : public Graph {}; +/// @brief Packman basic algorithm class PackageManager { public: - PackageManager(std::shared_ptr dep_graph) - : dependencies{dep_graph} {} + PackageManager() = delete; + PackageManager(DependencyGraph& dep_graph) : dependencies_{dep_graph} {} + /** + * @brief + * Finds the right order to install libraries in + * with respect to dependencies + * @param target Needed library + * @return std::vector + */ std::vector FindDownloadingOrder( - std::shared_ptr target); + std::shared_ptr> target); private: - std::shared_ptr dependencies; + void FindingOrderStep(std::shared_ptr> target); + DependencyGraph& dependencies_; + std::vector is_visited_; + std::stack reverse_order_; }; \ No newline at end of file From 4eb21cb66c88131b2ff393cfdc6627d12bfdc2cc Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 23 Sep 2024 14:28:23 +0000 Subject: [PATCH 13/42] Add indices methods --- lib/src/graph.hpp | 53 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 1397090..32aed2e 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -76,6 +76,16 @@ class Graph { */ size_t Size() { return vertices_.size(); } + /** + * @brief + * Add a directed edge between two vertices via indices + * @param source_id + * @param target_id + */ + void AddDirEdge(size_t source_id, size_t target_id) { + operator[](source_id)->adjacent.insert(operator[](target_id)); + } + /** * @brief * Add a directed edge between two vertices @@ -87,6 +97,18 @@ class Graph { source->adjacent.insert(target); } + /** + * @brief + * Remove a directed edge between two vertices via indices + * @param source_id + * @param target_id + */ + void RemoveDirEdge(size_t source_id, size_t target_id) { + operator[](source_id)->adjacent.erase(*std::find( + operator[](source_id)->adjacent.begin(), + operator[](source_id)->adjacent.end(), operator[](target_id))); + } + /** * @brief * Remove a directed edge between two vertices @@ -95,16 +117,26 @@ class Graph { */ void RemoveDirEdge(std::shared_ptr> source, std::shared_ptr> target) { - // std::find(source->adjacent.begin(), source->adjacent.end(), target); source->adjacent.erase( *std::find(source->adjacent.begin(), source->adjacent.end(), target)); } + /** + * @brief + * Add a non-directed edge between two vertices via indices + * @param first_id + * @param second_id + */ + void AddEdge(size_t first_id, std::shared_ptr> second_id) { + AddDirEdge(first_id, second_id); + AddDirEdge(second_id, first_id); + } + /** * @brief * Add a non-directed edge between two vertices - * @param source - * @param target + * @param vertex_1 + * @param vertex_2 */ void AddEdge(std::shared_ptr> vertex_1, std::shared_ptr> vertex_2) { @@ -112,11 +144,22 @@ class Graph { AddDirEdge(vertex_2, vertex_1); } + /** + * @brief + * Remove a non-directed edge between two vertices via indices + * @param first_id + * @param second_id + */ + void RemoveEdge(size_t first_id, size_t second_id) { + RemoveDirEdge(first_id, second_id); + RemoveDirEdge(second_id, first_id); + } + /** * @brief * Remove a non-directed edge between two vertices - * @param source - * @param target + * @param vertex_1 + * @param vertex_2 */ void RemoveEdge(std::shared_ptr> vertex_1, std::shared_ptr> vertex_2) { From c84a76b1c127071b1617934c73d94f83953a7247 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 23 Sep 2024 14:30:13 +0000 Subject: [PATCH 14/42] Output impovment --- task_01/src/main.cpp | 10 +++++----- task_01/src/packman.cpp | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp index 2ed1511..e1d61ec 100644 --- a/task_01/src/main.cpp +++ b/task_01/src/main.cpp @@ -9,11 +9,11 @@ int main() { dg_1.AddVertex("Lib_4"); dg_1.AddVertex("Lib_5"); - dg_1.AddDirEdge(dg_1[0], dg_1[1]); - dg_1.AddDirEdge(dg_1[1], dg_1[2]); - dg_1.AddDirEdge(dg_1[2], dg_1[3]); - dg_1.AddDirEdge(dg_1[4], dg_1[1]); - dg_1.AddDirEdge(dg_1[0], dg_1[3]); + dg_1.AddDirEdge(0, 1); + dg_1.AddDirEdge(0, 2); + dg_1.AddDirEdge(2, 3); + dg_1.AddDirEdge(3, 1); + dg_1.AddDirEdge(0, 3); PackageManager packman_1(dg_1); diff --git a/task_01/src/packman.cpp b/task_01/src/packman.cpp index 36c3f44..e831a90 100644 --- a/task_01/src/packman.cpp +++ b/task_01/src/packman.cpp @@ -20,7 +20,8 @@ std::vector PackageManager::FindDownloadingOrder( std::vector order; - std::cout << "Downloading Order is:" << std::endl; + std::cout << "Downloading Order for " << target->data + << " is:" << std::endl; while (reverse_order_.size() > 0) { order.push_back(reverse_order_.top()); std::cout << reverse_order_.top() << " "; From e2f2f28f8585d8504c6ce4d046ad3438e6a1aa21 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 23 Sep 2024 14:32:15 +0000 Subject: [PATCH 15/42] Fomat --- task_01/src/packman.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/task_01/src/packman.cpp b/task_01/src/packman.cpp index e831a90..9deadf2 100644 --- a/task_01/src/packman.cpp +++ b/task_01/src/packman.cpp @@ -20,8 +20,7 @@ std::vector PackageManager::FindDownloadingOrder( std::vector order; - std::cout << "Downloading Order for " << target->data - << " is:" << std::endl; + std::cout << "Downloading Order for " << target->data << " is:" << std::endl; while (reverse_order_.size() > 0) { order.push_back(reverse_order_.top()); std::cout << reverse_order_.top() << " "; From 7a6280a06513bf9885b9c56874807e015610d19f Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Tue, 24 Sep 2024 05:38:47 +0000 Subject: [PATCH 16/42] Topology sort algorithm + tests (have some issues with packman algo) --- task_01/src/main.cpp | 3 +- task_01/src/packman.cpp | 14 +++-- task_01/src/packman.hpp | 4 +- task_01/src/test.cpp | 110 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 120 insertions(+), 11 deletions(-) diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp index e1d61ec..32473f8 100644 --- a/task_01/src/main.cpp +++ b/task_01/src/main.cpp @@ -17,6 +17,5 @@ int main() { PackageManager packman_1(dg_1); - for (size_t j = 0; j < dg_1.Size(); ++j) - packman_1.FindDownloadingOrder(dg_1[j]); + packman_1.FindDownloadingOrder(); } diff --git a/task_01/src/packman.cpp b/task_01/src/packman.cpp index 9deadf2..18ec460 100644 --- a/task_01/src/packman.cpp +++ b/task_01/src/packman.cpp @@ -3,24 +3,28 @@ void PackageManager::FindingOrderStep( std::shared_ptr> target) { is_visited_[dependencies_.Find(target)] = true; - reverse_order_.push(target->data); + for (auto& neighbor : target->adjacent) { if (!is_visited_[dependencies_.Find(neighbor)]) { FindingOrderStep(neighbor); } } + + reverse_order_.push(target->data); } -std::vector PackageManager::FindDownloadingOrder( - std::shared_ptr> target) { +std::vector PackageManager::FindDownloadingOrder(/* + std::shared_ptr> target*/) { is_visited_.resize(dependencies_.Size()); for (size_t i = 0; i < is_visited_.size(); ++i) is_visited_[i] = false; - FindingOrderStep(target); + for (size_t i = 0; i < dependencies_.Size(); ++i) + if (!is_visited_[i]) FindingOrderStep(dependencies_[i]); std::vector order; - std::cout << "Downloading Order for " << target->data << " is:" << std::endl; + std::cout << "Downloading Order for " + << /*target->data <<*/ " is:" << std::endl; while (reverse_order_.size() > 0) { order.push_back(reverse_order_.top()); std::cout << reverse_order_.top() << " "; diff --git a/task_01/src/packman.hpp b/task_01/src/packman.hpp index 87590ab..5347c67 100644 --- a/task_01/src/packman.hpp +++ b/task_01/src/packman.hpp @@ -20,8 +20,8 @@ class PackageManager { * @param target Needed library * @return std::vector */ - std::vector FindDownloadingOrder( - std::shared_ptr> target); + std::vector FindDownloadingOrder(/* + std::shared_ptr> target*/); private: void FindingOrderStep(std::shared_ptr> target); diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 87cef73..b56d7bb 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -1,5 +1,111 @@ #include -TEST(Test, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "packman.hpp" + +TEST(Test, Example_1) { + // Example 1: Small graph + DependencyGraph dg_1; + + dg_1.AddVertex("Basic_Package"); + dg_1.AddVertex("Extention"); + + dg_1.AddDirEdge(0, 1); + + PackageManager packman_1(dg_1); + + // std::vector> answers{{"Basic_Package"}, + // {"Basic_Package", "Extention"}}; + + std::vector answer{"Basic_Package", "Extention"}; + + ASSERT_EQ(answer, packman_1.FindDownloadingOrder()); +} + +TEST(Test, Example_2) { + // Example 2: Three vertices, one edge + DependencyGraph dg_2; + + dg_2.AddVertex("First"); + dg_2.AddVertex("Second"); + dg_2.AddVertex("Independent"); + + dg_2.AddDirEdge(0, 1); + + PackageManager packman_2(dg_2); + + // std::vector> answers{ + // {"First"}, {"First", "Second"}, {"Independent"}}; + + std::vector answer{{"Independent", "First", "Second"}}; + + ASSERT_EQ(answer, packman_2.FindDownloadingOrder()); +} + +TEST(Test, Example_3) { + // Example 3: Five vertices, more complex dependencies + DependencyGraph dg_3; + + dg_3.AddVertex("BaseLib"); + dg_3.AddVertex("TestLib"); + dg_3.AddVertex("DataLib"); + dg_3.AddVertex("AlgorithmLib"); + dg_3.AddVertex("ToolLib"); + + dg_3.AddDirEdge(0, 1); + dg_3.AddDirEdge(0, 2); + dg_3.AddDirEdge(2, 3); + dg_3.AddDirEdge(3, 4); + + PackageManager packman_3(dg_3); + + // std::vector> answers{ + // {"BaseLib"}, + // {"BaseLib", "TestLib"}, + // {"BaseLib", "DataLib"}, + // {"BaseLib", "DataLib", "AlgorithmLib"}, + // {"BaseLib", "DataLib", "AlgorithmLib", "ToolLib"}}; + + std::vector answer{"BaseLib", "DataLib", "AlgorithmLib", + "ToolLib", "TestLib"}; + + ASSERT_EQ(answer, packman_3.FindDownloadingOrder()); +} + +TEST(Test, Example_4) { + // Example 4: More complex graph, multiple paths + DependencyGraph dg_4; + + dg_4.AddVertex("Start"); + dg_4.AddVertex("A1"); + dg_4.AddVertex("A2"); + dg_4.AddVertex("B1"); + dg_4.AddVertex("B2"); + dg_4.AddVertex("C1"); + dg_4.AddVertex("C2"); + dg_4.AddVertex("End"); + + dg_4.AddDirEdge(0, 1); + dg_4.AddDirEdge(0, 2); + dg_4.AddDirEdge(1, 3); + dg_4.AddDirEdge(2, 4); + dg_4.AddDirEdge(3, 5); + dg_4.AddDirEdge(4, 6); + dg_4.AddDirEdge(5, 7); + dg_4.AddDirEdge(6, 7); + PackageManager packman_4(dg_4); + + // std::vector> answers{ + // {"Start"}, + // {"Start", "A1"}, + // {"Start", "A2"}, + // {"Start", "A1", "B1"}, + // {"Start", "A2", "B2"}, + // {"Start", "A1", "B1", "C1"}, + // {"Start", "A2", "B2", "C2"}, + // {"Start", "A1", "B1", "C1", "A2", "B2", "C2", "End"}}; + + std::vector answer{"Start", "A1", "B1", "C1", + "A2", "B2", "C2", "End"}; + + ASSERT_EQ(answer, packman_4.FindDownloadingOrder()); } \ No newline at end of file From 4f1a34d273ff69cef9acdde3c5fbb911a556ee36 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 4 Oct 2024 15:10:38 +0000 Subject: [PATCH 17/42] resolve conflict --- task_01/src/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp index 32473f8..96f74c4 100644 --- a/task_01/src/main.cpp +++ b/task_01/src/main.cpp @@ -18,4 +18,6 @@ int main() { PackageManager packman_1(dg_1); packman_1.FindDownloadingOrder(); + + return 0; } From d5457942ee1ec455cad036d89f36a2d92f164447 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Thu, 31 Oct 2024 12:49:35 +0000 Subject: [PATCH 18/42] codestyle improvement --- lib/src/graph.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 32aed2e..ca14a68 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -33,6 +33,7 @@ class Graph { std::shared_ptr> operator[](size_t index) { return vertices_[index]; } + const std::shared_ptr> operator[](size_t index) const { return vertices_[index]; } @@ -43,7 +44,7 @@ class Graph { * @param vertex * @return size_t */ - size_t Find(const std::shared_ptr> &vertex) { + size_t Find(const std::shared_ptr> &vertex) const { return std::find(vertices_.begin(), vertices_.end(), vertex) - vertices_.begin(); }; @@ -74,7 +75,7 @@ class Graph { * Returns the number of vertices in the graph * @return size_t */ - size_t Size() { return vertices_.size(); } + size_t Size() const { return vertices_.size(); } /** * @brief @@ -127,7 +128,7 @@ class Graph { * @param first_id * @param second_id */ - void AddEdge(size_t first_id, std::shared_ptr> second_id) { + void AddEdge(size_t first_id, size_t second_id) { AddDirEdge(first_id, second_id); AddDirEdge(second_id, first_id); } @@ -181,6 +182,6 @@ class Graph { } } - private: + protected: std::vector>> vertices_; }; From d4966eaf1556962b276f685184066b7b7dfb4cdc Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Thu, 31 Oct 2024 12:57:37 +0000 Subject: [PATCH 19/42] apply some clang-tidy suggestions --- task_01/src/packman.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/task_01/src/packman.hpp b/task_01/src/packman.hpp index 5347c67..fdf286f 100644 --- a/task_01/src/packman.hpp +++ b/task_01/src/packman.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include @@ -25,7 +27,7 @@ class PackageManager { private: void FindingOrderStep(std::shared_ptr> target); - DependencyGraph& dependencies_; - std::vector is_visited_; - std::stack reverse_order_; + DependencyGraph dependencies_; + std::vector is_visited_{}; + std::stack reverse_order_{}; }; \ No newline at end of file From 474f6a6ee35f4cee07fbadd021f2942af6a71ce0 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Thu, 31 Oct 2024 14:27:40 +0000 Subject: [PATCH 20/42] made function return beridges and cut vertices, fixed tests due to this --- task_02/src/main.cpp | 14 ++++- task_02/src/network.cpp | 14 +---- task_02/src/network.hpp | 3 +- task_02/src/test.cpp | 126 ++++++++++++++++++++++------------------ 4 files changed, 88 insertions(+), 69 deletions(-) diff --git a/task_02/src/main.cpp b/task_02/src/main.cpp index 17f2e9d..2894da4 100644 --- a/task_02/src/main.cpp +++ b/task_02/src/main.cpp @@ -16,5 +16,17 @@ int main() { network.AddEdge(2, 0); network.AddEdge(2, 3); - network.FindBridgesAndCutVertices(); + auto [bridges, cut_vertices] = network.FindBridgesAndCutVertices(); + + // Print bridges + std::cout << "Bridges:" << std::endl; + for (const auto &bridge : bridges) + std::cout << bridge.first << " -- " << bridge.second << std::endl; + + // Print cut vertices + std::cout << "Cut vertices:" << std::endl; + for (const auto &cut_vertex : cut_vertices) + std::cout << cut_vertex << std::endl; + + return 0; } \ No newline at end of file diff --git a/task_02/src/network.cpp b/task_02/src/network.cpp index b4f434e..c973144 100644 --- a/task_02/src/network.cpp +++ b/task_02/src/network.cpp @@ -40,7 +40,8 @@ void Network::TarjanVisit(size_t vertex_id, std::vector &disc, cut_vertices.push_back(vertex_id); } -void Network::FindBridgesAndCutVertices() { +std::pair>, std::vector> +Network::FindBridgesAndCutVertices() { std::vector disc(Size(), -1); std::vector low(Size(), -1); std::vector parent(Size(), -1); @@ -51,14 +52,5 @@ void Network::FindBridgesAndCutVertices() { for (size_t vertex_id = 0; vertex_id < Size(); ++vertex_id) if (disc[vertex_id] == -1) TarjanVisit(vertex_id, disc, low, parent, bridges, cut_vertices, time); - - // Print bridges - std::cout << "Bridges:" << std::endl; - for (const auto &bridge : bridges) - std::cout << bridge.first << " -- " << bridge.second << std::endl; - - // Print cut vertices - std::cout << "Cut vertices:" << std::endl; - for (const auto &cut_vertex : cut_vertices) - std::cout << cut_vertex << std::endl; + return std::make_pair(bridges, cut_vertices); } \ No newline at end of file diff --git a/task_02/src/network.hpp b/task_02/src/network.hpp index cf11ee1..7e36cca 100644 --- a/task_02/src/network.hpp +++ b/task_02/src/network.hpp @@ -6,7 +6,8 @@ class Network : public Graph { public: /// @brief Finds bridges and cut vertices in graph using Tarjan's algorithm - void FindBridgesAndCutVertices(); + std::pair>, std::vector> + FindBridgesAndCutVertices(); private: void TarjanVisit(size_t vertex_id, std::vector &disc, diff --git a/task_02/src/test.cpp b/task_02/src/test.cpp index 0885877..d97be12 100644 --- a/task_02/src/test.cpp +++ b/task_02/src/test.cpp @@ -1,25 +1,43 @@ #include -#include +#include +#include #include "network.hpp" -class NetworkTest : public ::testing::Test { - protected: - Network network; -}; - -// Helper function to capture cout output -std::string CaptureCoutOutput(std::function func) { - std::stringstream buffer; - std::streambuf* old = std::cout.rdbuf(buffer.rdbuf()); - func(); - std::cout.rdbuf(old); - return buffer.str(); +// Helper function to check if a bridge exists +bool BridgeExists(const std::vector>& bridges, int u, + int v) { + return std::find_if(bridges.begin(), bridges.end(), + [u, v](const auto& bridge) { + return (bridge.first == u && bridge.second == v) || + (bridge.first == v && bridge.second == u); + }) != bridges.end(); +} + +// Helper function to check if returned bridges are correct +void CheckBridges(const std::vector>& bridges, + const std::vector>& expected_bridges) { + EXPECT_EQ(bridges.size(), expected_bridges.size()); + for (const auto& bridge : expected_bridges) + EXPECT_TRUE(BridgeExists(bridges, bridge.first, bridge.second)); +} + +// Helper function to check if two sets of integers are equal +bool SetsEqual(const std::vector& vec1, const std::vector& vec2) { + std::set set1(vec1.begin(), vec1.end()); + std::set set2(vec2.begin(), vec2.end()); + return set1 == set2; } -TEST_F(NetworkTest, SimpleTriangleWithBridge) { - // Create a triangle with a single bridge +// Helper function to check if returned cut vertices are correct +void CheckCutVertices(const std::vector& cut_vertices, + const std::vector& expected_cut_vertices) { + EXPECT_TRUE(SetsEqual(cut_vertices, expected_cut_vertices)); +} + +TEST(NetworkTest, SimpleTriangleWithBridge) { + Network network; network.AddVertex(0); network.AddVertex(1); network.AddVertex(2); @@ -30,17 +48,17 @@ TEST_F(NetworkTest, SimpleTriangleWithBridge) { network.AddEdge(2, 0); network.AddEdge(2, 3); // This is a bridge - std::string output = - CaptureCoutOutput([&]() { network.FindBridgesAndCutVertices(); }); + auto [bridges, cut_vertices] = network.FindBridgesAndCutVertices(); + + std::vector> excepted_bridges = {{2, 3}}; + std::vector excepted_cut_vertices = {2}; - // Check if bridge 2-3 is detected - EXPECT_TRUE(output.find("2 -- 3") != std::string::npos); - // Vertex 2 should be a cut vertex - EXPECT_TRUE(output.find("Cut vertices:\n2") != std::string::npos); + CheckBridges(bridges, excepted_bridges); + CheckCutVertices(cut_vertices, excepted_cut_vertices); } -TEST_F(NetworkTest, NoBridgesOrCutVertices) { - // Create a complete graph with 3 vertices (triangle) +TEST(NetworkTest, NoBridgesOrCutVertices) { + Network network; network.AddVertex(0); network.AddVertex(1); network.AddVertex(2); @@ -49,16 +67,17 @@ TEST_F(NetworkTest, NoBridgesOrCutVertices) { network.AddEdge(1, 2); network.AddEdge(2, 0); - std::string output = - CaptureCoutOutput([&]() { network.FindBridgesAndCutVertices(); }); + auto [bridges, cut_vertices] = network.FindBridgesAndCutVertices(); + + std::vector> excepted_bridges = {}; + std::vector excepted_cut_vertices = {}; - // Should not find any bridges or cut vertices - EXPECT_TRUE(output.find("Bridges:\n") != std::string::npos); - EXPECT_TRUE(output.find("Cut vertices:\n") != std::string::npos); + CheckBridges(bridges, excepted_bridges); + CheckCutVertices(cut_vertices, excepted_cut_vertices); } -TEST_F(NetworkTest, LineGraph) { - // Create a line graph where all edges are bridges +TEST(NetworkTest, LineGraph) { + Network network; network.AddVertex(0); network.AddVertex(1); network.AddVertex(2); @@ -66,50 +85,45 @@ TEST_F(NetworkTest, LineGraph) { network.AddEdge(0, 1); network.AddEdge(1, 2); - std::string output = - CaptureCoutOutput([&]() { network.FindBridgesAndCutVertices(); }); + auto [bridges, cut_vertices] = network.FindBridgesAndCutVertices(); + + std::vector> excepted_bridges = {{0, 1}, {1, 2}}; + std::vector excepted_cut_vertices = {1}; - // All edges should be bridges - EXPECT_TRUE(output.find("0 -- 1") != std::string::npos); - EXPECT_TRUE(output.find("1 -- 2") != std::string::npos); - // Middle vertex should be a cut vertex - EXPECT_TRUE(output.find("Cut vertices:\n1") != std::string::npos); + CheckBridges(bridges, excepted_bridges); + CheckCutVertices(cut_vertices, excepted_cut_vertices); } -TEST_F(NetworkTest, EmptyGraph) { - std::string output = - CaptureCoutOutput([&]() { network.FindBridgesAndCutVertices(); }); +TEST(NetworkTest, EmptyGraph) { + Network network; + auto [bridges, cut_vertices] = network.FindBridgesAndCutVertices(); + + std::vector> excepted_bridges = {}; + std::vector excepted_cut_vertices = {}; - // Should not find any bridges or cut vertices - EXPECT_TRUE(output.find("Bridges:\n") != std::string::npos); - EXPECT_TRUE(output.find("Cut vertices:\n") != std::string::npos); + CheckBridges(bridges, excepted_bridges); + CheckCutVertices(cut_vertices, excepted_cut_vertices); } -TEST_F(NetworkTest, CycleWithMultipleBridges) { - // Create a more complex graph with multiple bridges and cut vertices +TEST(NetworkTest, CycleWithMultipleBridges) { + Network network; network.AddVertex(0); network.AddVertex(1); network.AddVertex(2); network.AddVertex(3); network.AddVertex(4); - // Create a cycle 0-1-2 network.AddEdge(0, 1); network.AddEdge(1, 2); network.AddEdge(2, 0); - - // Add bridges network.AddEdge(1, 3); // Bridge to vertex 3 network.AddEdge(3, 4); // Bridge to vertex 4 - std::string output = - CaptureCoutOutput([&]() { network.FindBridgesAndCutVertices(); }); + auto [bridges, cut_vertices] = network.FindBridgesAndCutVertices(); - // Check for bridges - EXPECT_TRUE(output.find("1 -- 3") != std::string::npos); - EXPECT_TRUE(output.find("3 -- 4") != std::string::npos); + std::vector> excepted_bridges = {{1, 3}, {3, 4}}; + std::vector excepted_cut_vertices = {1, 3}; - // Vertices 1 and 3 should be cut vertices - EXPECT_TRUE(output.find("1") != std::string::npos); - EXPECT_TRUE(output.find("3") != std::string::npos); + CheckBridges(bridges, excepted_bridges); + CheckCutVertices(cut_vertices, excepted_cut_vertices); } \ No newline at end of file From 158b66964eec0795f7ad854f373e417636c0f3c1 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Thu, 31 Oct 2024 14:28:40 +0000 Subject: [PATCH 21/42] add missing '#pragma once' --- task_01/src/packman.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/task_01/src/packman.hpp b/task_01/src/packman.hpp index 5347c67..4fbea16 100644 --- a/task_01/src/packman.hpp +++ b/task_01/src/packman.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include From e202e3d7c88e25c6e3382854c1e2f633d22c38b3 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 1 Nov 2024 11:15:45 +0000 Subject: [PATCH 22/42] added weighted graph class --- lib/src/graph.hpp | 57 ++++++++++------- lib/src/weighted_graph.hpp | 122 +++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 21 deletions(-) create mode 100644 lib/src/weighted_graph.hpp diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index ca14a68..19b8317 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -26,7 +26,7 @@ class Graph { * Add a new vertex to the graph * @param data */ - void AddVertex(const T &data) { + virtual void AddVertex(const T &data) { vertices_.push_back(std::make_shared>(data)); }; @@ -49,12 +49,32 @@ class Graph { vertices_.begin(); }; + /** + * @brief + * Remove a vertex from the graph via index + * @param vertex_id + */ + virtual void RemoveVertex(size_t vertex_id) { + if (vertex_id >= Size()) { + // Vertex not found + return; + } + + // Remove edges pointing to the vertex + for (auto &v : vertices_[vertex_id]->adjacent) { + RemoveEdge(v, vertices_[vertex_id]); + } + + // Remove the vertex from the graph + vertices_.erase(vertices_.begin() + vertex_id); + } + /** * @brief * Remove a vertex from the graph * @param vertex */ - void RemoveVertex(std::shared_ptr> vertex) { + virtual void RemoveVertex(std::shared_ptr> vertex) { // Find the vertex in the graph auto it = std::find(vertices_.begin(), vertices_.end(), vertex); if (it == vertices_.end()) { @@ -62,12 +82,7 @@ class Graph { return; } - // Remove edges pointing to the vertex - for (auto &v : vertices_[it - vertices_.begin()]->adjacent) { - RemoveEdge(v, vertices_[it - vertices_.begin()]); - } - // Remove the vertex from the graph - vertices_.erase(it); + RemoveVertex(it - vertices_.begin()); } /** @@ -83,7 +98,7 @@ class Graph { * @param source_id * @param target_id */ - void AddDirEdge(size_t source_id, size_t target_id) { + virtual void AddDirEdge(size_t source_id, size_t target_id) { operator[](source_id)->adjacent.insert(operator[](target_id)); } @@ -93,8 +108,8 @@ class Graph { * @param source * @param target */ - void AddDirEdge(std::shared_ptr> source, - std::shared_ptr> target) { + virtual void AddDirEdge(std::shared_ptr> source, + std::shared_ptr> target) { source->adjacent.insert(target); } @@ -104,7 +119,7 @@ class Graph { * @param source_id * @param target_id */ - void RemoveDirEdge(size_t source_id, size_t target_id) { + virtual void RemoveDirEdge(size_t source_id, size_t target_id) { operator[](source_id)->adjacent.erase(*std::find( operator[](source_id)->adjacent.begin(), operator[](source_id)->adjacent.end(), operator[](target_id))); @@ -116,8 +131,8 @@ class Graph { * @param source * @param target */ - void RemoveDirEdge(std::shared_ptr> source, - std::shared_ptr> target) { + virtual void RemoveDirEdge(std::shared_ptr> source, + std::shared_ptr> target) { source->adjacent.erase( *std::find(source->adjacent.begin(), source->adjacent.end(), target)); } @@ -128,7 +143,7 @@ class Graph { * @param first_id * @param second_id */ - void AddEdge(size_t first_id, size_t second_id) { + virtual void AddEdge(size_t first_id, size_t second_id) { AddDirEdge(first_id, second_id); AddDirEdge(second_id, first_id); } @@ -139,8 +154,8 @@ class Graph { * @param vertex_1 * @param vertex_2 */ - void AddEdge(std::shared_ptr> vertex_1, - std::shared_ptr> vertex_2) { + virtual void AddEdge(std::shared_ptr> vertex_1, + std::shared_ptr> vertex_2) { AddDirEdge(vertex_1, vertex_2); AddDirEdge(vertex_2, vertex_1); } @@ -151,7 +166,7 @@ class Graph { * @param first_id * @param second_id */ - void RemoveEdge(size_t first_id, size_t second_id) { + virtual void RemoveEdge(size_t first_id, size_t second_id) { RemoveDirEdge(first_id, second_id); RemoveDirEdge(second_id, first_id); } @@ -162,8 +177,8 @@ class Graph { * @param vertex_1 * @param vertex_2 */ - void RemoveEdge(std::shared_ptr> vertex_1, - std::shared_ptr> vertex_2) { + virtual void RemoveEdge(std::shared_ptr> vertex_1, + std::shared_ptr> vertex_2) { RemoveDirEdge(vertex_1, vertex_2); RemoveDirEdge(vertex_2, vertex_1); } @@ -172,7 +187,7 @@ class Graph { * @brief * Print the adjacency list of the graph */ - void PrintGraph() const { + virtual void PrintGraph() const { for (const auto &vertex : vertices_) { std::cout << vertex->data << " -> "; for (const auto &neighbor : vertex->adjacent) { diff --git a/lib/src/weighted_graph.hpp b/lib/src/weighted_graph.hpp new file mode 100644 index 0000000..63423cc --- /dev/null +++ b/lib/src/weighted_graph.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include + +#include "graph.hpp" + +/// @brief Basic weighted graph +/// @tparam T +template +class WeightedGraph : public Graph { + public: + WeightedGraph() : Graph() { + weights.resize(Graph::vertices_.size(), + std::vector(Graph::vertices_.size(), + std::numeric_limits::max())); + } + + /** + * @brief + * Override AddVertex to handle weights matrix resizing + * @param data + */ + void AddVertex(const T& data) override { + Graph::AddVertex(data); + weights.resize(Graph::vertices_.size(), + std::vector(Graph::vertices_.size(), + std::numeric_limits::max())); + for (auto& row : weights) + row.resize(Graph::vertices_.size(), std::numeric_limits::max()); + } + + /** + * @brief + * Override RemoveVertex via index to handle weights matrix resizing + * @param vertex_id + */ + void RemoveVertex(size_t vertex_id) override { + // Remove the vertex from the base class + Graph::RemoveVertex(vertex_id); + + // Remove the corresponding row and column from the weights matrix + weights.erase(weights.begin() + vertex_id); // Remove the row + + for (auto& row : weights) + row.erase(row.begin() + vertex_id); // Remove the column + } + + /** + * @brief + * Add a weighted directed edge + * @param source_id + * @param target_id + * @param weight + */ + void AddDirEdge(size_t source_id, size_t target_id, int weight) { + Graph::AddDirEdge(source_id, target_id); + weights[source_id][target_id] = weight; + } + + /** + * @brief + * Add a weighted undirected edge + * @param source_id + * @param target_id + * @param weight + */ + void AddEdge(size_t source_id, size_t target_id, int weight) { + AddDirEdge(source_id, target_id, weight); + AddDirEdge(target_id, source_id, weight); + } + + /** + * @brief + * Remove a weighted directed edge + * @param source_id + * @param target_id + */ + void RemoveDirEdge(size_t source_id, size_t target_id) override { + Graph::RemoveDirEdge(source_id, target_id); + weights[source_id][target_id] = std::numeric_limits::max(); + } + + /** + * @brief + * Remove a weighted undirected edge + * @param source_id + * @param target_id + */ + void RemoveEdge(size_t source_id, size_t target_id) override { + RemoveDirEdge(source_id, target_id); + RemoveDirEdge(target_id, source_id); + } + + /** + * @brief + * Get the weight of an edge + * @param source_id + * @param target_id + * @return int + */ + int GetWeight(size_t source_id, size_t target_id) const { + return weights[source_id][target_id]; + } + + /** + * @brief + * Print the weighted graph + */ + void PrintGraph() const override { + for (size_t i = 0; i < Graph::vertices_.size(); ++i) { + std::cout << Graph::vertices_[i]->data << " -> "; + for (const auto& neighbor : Graph::vertices_[i]->adjacent) { + size_t j = Graph::Find(neighbor); + std::cout << "(" << neighbor->data << ", " << weights[i][j] << ") "; + } + std::cout << std::endl; + } + } + + private: + std::vector> weights; +}; \ No newline at end of file From b5c3636f2c4d903412c29f0d8ffca861baa87a74 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 1 Nov 2024 11:15:58 +0000 Subject: [PATCH 23/42] task_04 --- task_04/src/djikstra.hpp | 84 ++++++++++++++++++++++++++++++++++ task_04/src/test.cpp | 97 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 task_04/src/djikstra.hpp diff --git a/task_04/src/djikstra.hpp b/task_04/src/djikstra.hpp new file mode 100644 index 0000000..4b4e845 --- /dev/null +++ b/task_04/src/djikstra.hpp @@ -0,0 +1,84 @@ +#pragma once +#include + +#include "weighted_graph.hpp" + +template +std::pair, std::vector> Dijkstra( + const WeightedGraph& graph, size_t start) { + const size_t size = graph.Size(); + + // Distance array to store shortest distances from start + std::vector distances(size, std::numeric_limits::max()); + + // Previous vertex array to reconstruct the path + std::vector previous(size, -1); + + // Visited set to keep track of processed vertices + std::vector visited(size, false); + + // Priority queue to get vertex with minimum distance + // pair: (distance, vertex_index) + std::priority_queue, + std::vector>, std::greater<>> + pq; + + // Initialize distance to start vertex as 0 + distances[start] = 0; + pq.push({0, start}); + + while (!pq.empty()) { + size_t current = pq.top().second; + pq.pop(); + + // Skip if already visited + if (visited[current]) continue; + + visited[current] = true; + + // For each adjacent vertex of current vertex + for (const auto& neighbor : graph[current]->adjacent) { + size_t next = graph.Find(neighbor); + int weight = graph.GetWeight(current, next); + + // If we found a shorter path to neighbor + if (!visited[next] && + distances[current] != std::numeric_limits::max() && + distances[current] + weight < distances[next]) { + distances[next] = distances[current] + weight; + previous[next] = current; + pq.push({distances[next], next}); + } + } + } + + return {distances, previous}; +} + +/** + * @brief + * Reconstruct path from start to end vertex + * @tparam T + * @param previous + * @param start + * @param end + * @return std::vector path + */ +template +std::vector GetPath(const std::vector& previous, size_t start, + size_t end) { + std::vector path; + + // If there's no path to end + if (previous[end] == -1 && end != start) return path; + + // Reconstruct path by walking backwards from end to start + for (size_t current = end; current != -1; current = previous[current]) { + path.push_back(current); + if (current == start) break; + } + + // Reverse path to get start->end order + std::reverse(path.begin(), path.end()); + return path; +} \ No newline at end of file diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 5e11617..e259746 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,97 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "djikstra.hpp" +#include "weighted_graph.hpp" + +void CheckDistances(std::vector& dist, std::vector& exp_dist) { + EXPECT_EQ(dist.size(), exp_dist.size()); + for (size_t i = 0; i < dist.size(); ++i) EXPECT_EQ(dist[i], exp_dist[i]); } + +void CheckPaths(std::vector& prev, + std::vector>& exp_paths, size_t source) { + for (size_t i = 0; i < prev.size(); ++i) { + std::vector path = GetPath(prev, source, i); + EXPECT_EQ(path, exp_paths[i]); + } +} + +TEST(DijkstraTest, SimpleUndirectedGraph) { + WeightedGraph graph; + + // Add vertices + for (int i = 0; i < 5; i++) graph.AddVertex(i); + + // Add edges + graph.AddEdge(0, 1, 4); + graph.AddEdge(0, 2, 2); + graph.AddEdge(1, 2, 1); + graph.AddEdge(1, 3, 5); + graph.AddEdge(2, 3, 8); + graph.AddEdge(2, 4, 10); + graph.AddEdge(3, 4, 2); + + size_t source = 0; + + auto [distances, previous] = Dijkstra(graph, source); + + std::vector expected_distances = {0, 3, 2, 8, 10}; + + CheckDistances(distances, expected_distances); + + std::vector> expected_paths = { + {0}, {0, 2, 1}, {0, 2}, {0, 2, 1, 3}, {0, 2, 1, 3, 4}}; + + CheckPaths(previous, expected_paths, source); +} + +TEST(DijkstraTest, SimpleDirectedGraph) { + WeightedGraph graph; + + // Add vertices + for (int i = 0; i < 5; i++) graph.AddVertex(i); + + // Add edges + graph.AddDirEdge(0, 1, 4); + graph.AddDirEdge(0, 2, 2); + graph.AddDirEdge(1, 2, 1); + graph.AddDirEdge(1, 3, 5); + graph.AddDirEdge(2, 3, 8); + graph.AddDirEdge(2, 4, 10); + graph.AddDirEdge(3, 4, 2); + + size_t source = 0; + + auto [distances, previous] = Dijkstra(graph, source); + + std::vector expected_distances = {0, 4, 2, 9, 11}; + + CheckDistances(distances, expected_distances); + + std::vector> expected_paths = { + {0}, {0, 1}, {0, 2}, {0, 1, 3}, {0, 1, 3, 4}}; + + CheckPaths(previous, expected_paths, source); +} + +TEST(DijkstraTest, DisconnectedGraph) { + WeightedGraph graph; + + // Add vertices + for (int i = 0; i < 3; i++) graph.AddVertex(i); + + // Add single edge + graph.AddDirEdge(0, 1, 5); + + size_t source = 0; + + auto [distances, previous] = Dijkstra(graph, source); + + std::vector expected_distances = {0, 5, std::numeric_limits::max()}; + + CheckDistances(distances, expected_distances); + + std::vector> expected_paths = {{0}, {0, 1}, {}}; + + CheckPaths(previous, expected_paths, source); +} \ No newline at end of file From 8221b80835d3ae0889a3dd7728cf9268255f4510 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 15 Nov 2024 12:06:08 +0000 Subject: [PATCH 24/42] fix graph methods --- lib/src/graph.hpp | 13 ++++++++----- lib/src/weighted_graph.hpp | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 19b8317..0558d7f 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -44,10 +44,13 @@ class Graph { * @param vertex * @return size_t */ - size_t Find(const std::shared_ptr> &vertex) const { - return std::find(vertices_.begin(), vertices_.end(), vertex) - - vertices_.begin(); - }; + size_t Find(const T &vertex) const { + size_t index; + for (index = 0; index < vertices_.size(); ++index) + if (vertices_[index]->data == vertex) return index; + + return index; + } /** * @brief @@ -62,7 +65,7 @@ class Graph { // Remove edges pointing to the vertex for (auto &v : vertices_[vertex_id]->adjacent) { - RemoveEdge(v, vertices_[vertex_id]); + RemoveDirEdge(v, vertices_[vertex_id]); } // Remove the vertex from the graph diff --git a/lib/src/weighted_graph.hpp b/lib/src/weighted_graph.hpp index 63423cc..487768a 100644 --- a/lib/src/weighted_graph.hpp +++ b/lib/src/weighted_graph.hpp @@ -110,7 +110,7 @@ class WeightedGraph : public Graph { for (size_t i = 0; i < Graph::vertices_.size(); ++i) { std::cout << Graph::vertices_[i]->data << " -> "; for (const auto& neighbor : Graph::vertices_[i]->adjacent) { - size_t j = Graph::Find(neighbor); + size_t j = Graph::Find(neighbor->data); std::cout << "(" << neighbor->data << ", " << weights[i][j] << ") "; } std::cout << std::endl; From d861367fc5c47bb9a00ca062e078ffe3babf0f1b Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 15 Nov 2024 12:07:00 +0000 Subject: [PATCH 25/42] add corresponding changes in tasks --- task_01/src/packman.cpp | 4 ++-- task_02/src/network.cpp | 2 +- task_04/src/djikstra.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/task_01/src/packman.cpp b/task_01/src/packman.cpp index 18ec460..acb326d 100644 --- a/task_01/src/packman.cpp +++ b/task_01/src/packman.cpp @@ -2,10 +2,10 @@ void PackageManager::FindingOrderStep( std::shared_ptr> target) { - is_visited_[dependencies_.Find(target)] = true; + is_visited_[dependencies_.Find(target->data)] = true; for (auto& neighbor : target->adjacent) { - if (!is_visited_[dependencies_.Find(neighbor)]) { + if (!is_visited_[dependencies_.Find(neighbor->data)]) { FindingOrderStep(neighbor); } } diff --git a/task_02/src/network.cpp b/task_02/src/network.cpp index c973144..8dfb7e4 100644 --- a/task_02/src/network.cpp +++ b/task_02/src/network.cpp @@ -12,7 +12,7 @@ void Network::TarjanVisit(size_t vertex_id, std::vector &disc, // Iterate over all adjacent vertices for (auto &neighbor : vertices_[vertex_id]->adjacent) { - size_t neighbor_id = Find(neighbor); + size_t neighbor_id = Find(neighbor->data); if (disc[neighbor_id] == -1) { // Vertex is not visited children++; diff --git a/task_04/src/djikstra.hpp b/task_04/src/djikstra.hpp index 4b4e845..c538f40 100644 --- a/task_04/src/djikstra.hpp +++ b/task_04/src/djikstra.hpp @@ -38,7 +38,7 @@ std::pair, std::vector> Dijkstra( // For each adjacent vertex of current vertex for (const auto& neighbor : graph[current]->adjacent) { - size_t next = graph.Find(neighbor); + size_t next = graph.Find(neighbor->data); int weight = graph.GetWeight(current, next); // If we found a shorter path to neighbor From 1d2d2044f6954abcd855613b7070e20195e8b475 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 15 Nov 2024 18:38:32 +0000 Subject: [PATCH 26/42] add djikstra library --- task_04/CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/task_04/CMakeLists.txt b/task_04/CMakeLists.txt index 7c1cb30..3e59eba 100644 --- a/task_04/CMakeLists.txt +++ b/task_04/CMakeLists.txt @@ -9,7 +9,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) file(GLOB_RECURSE source_list "src/*.cpp" "src/*.hpp") file(GLOB_RECURSE main_source_list "src/main.cpp") -file(GLOB_RECURSE test_source_list "src/*.cpp") +file(GLOB_RECURSE test_source_list "src/*.cpp" "src/*.hpp") file(GLOB_RECURSE test_list "src/*test.cpp") list(REMOVE_ITEM test_source_list ${main_source_list}) @@ -27,6 +27,12 @@ include_directories(${GTEST_INCLUDE_DIRS}) find_library(Utils ../) target_link_libraries(${PROJECT_NAME} PUBLIC Utils) +file(GLOB_RECURSE lib_source_list "src/*.hpp") + +add_library(Dijkstra ${lib_source_list}) + +set_target_properties(Dijkstra PROPERTIES LINKER_LANGUAGE CXX) + # Link runTests with what we want to test and the GTest and pthread library add_executable(${PROJECT_NAME}_tests ${test_source_list}) target_link_libraries( From 85afe6b138fe319ad41209d026c9858dd4c3e6ea Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 15 Nov 2024 18:46:57 +0000 Subject: [PATCH 27/42] fix naming --- task_04/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/task_04/CMakeLists.txt b/task_04/CMakeLists.txt index 3e59eba..61be238 100644 --- a/task_04/CMakeLists.txt +++ b/task_04/CMakeLists.txt @@ -29,9 +29,9 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Utils) file(GLOB_RECURSE lib_source_list "src/*.hpp") -add_library(Dijkstra ${lib_source_list}) +add_library(Djikstra ${lib_source_list}) -set_target_properties(Dijkstra PROPERTIES LINKER_LANGUAGE CXX) +set_target_properties(Djikstra PROPERTIES LINKER_LANGUAGE CXX) # Link runTests with what we want to test and the GTest and pthread library add_executable(${PROJECT_NAME}_tests ${test_source_list}) From ad128124433a8c0431934dd393a6cd2166797636 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 15 Nov 2024 19:16:06 +0000 Subject: [PATCH 28/42] add target include directories --- task_04/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/task_04/CMakeLists.txt b/task_04/CMakeLists.txt index 61be238..f11830e 100644 --- a/task_04/CMakeLists.txt +++ b/task_04/CMakeLists.txt @@ -33,6 +33,8 @@ add_library(Djikstra ${lib_source_list}) set_target_properties(Djikstra PROPERTIES LINKER_LANGUAGE CXX) +target_include_directories(Djikstra PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) + # Link runTests with what we want to test and the GTest and pthread library add_executable(${PROJECT_NAME}_tests ${test_source_list}) target_link_libraries( From 0d34e44e122545b7533727f557ec46647a9fc1f3 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 15 Nov 2024 19:25:23 +0000 Subject: [PATCH 29/42] final fix naming(djikstra->dijkstra) --- task_04/CMakeLists.txt | 6 +++--- task_04/src/{djikstra.hpp => dijkstra.hpp} | 0 task_04/src/test.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename task_04/src/{djikstra.hpp => dijkstra.hpp} (100%) diff --git a/task_04/CMakeLists.txt b/task_04/CMakeLists.txt index f11830e..a90cc12 100644 --- a/task_04/CMakeLists.txt +++ b/task_04/CMakeLists.txt @@ -29,11 +29,11 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Utils) file(GLOB_RECURSE lib_source_list "src/*.hpp") -add_library(Djikstra ${lib_source_list}) +add_library(Dijkstra ${lib_source_list}) -set_target_properties(Djikstra PROPERTIES LINKER_LANGUAGE CXX) +set_target_properties(Dijkstra PROPERTIES LINKER_LANGUAGE CXX) -target_include_directories(Djikstra PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) +target_include_directories(Dijkstra PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) # Link runTests with what we want to test and the GTest and pthread library add_executable(${PROJECT_NAME}_tests ${test_source_list}) diff --git a/task_04/src/djikstra.hpp b/task_04/src/dijkstra.hpp similarity index 100% rename from task_04/src/djikstra.hpp rename to task_04/src/dijkstra.hpp diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index e259746..9fc4a27 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,6 @@ #include -#include "djikstra.hpp" +#include "dijkstra.hpp" #include "weighted_graph.hpp" void CheckDistances(std::vector& dist, std::vector& exp_dist) { From b7cce0e67f77d067cee81756eb9e9ab891ddca16 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 15 Nov 2024 22:43:08 +0000 Subject: [PATCH 30/42] add reweight() method --- lib/src/weighted_graph.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/src/weighted_graph.hpp b/lib/src/weighted_graph.hpp index 487768a..dcea94c 100644 --- a/lib/src/weighted_graph.hpp +++ b/lib/src/weighted_graph.hpp @@ -102,6 +102,17 @@ class WeightedGraph : public Graph { return weights[source_id][target_id]; } + /** + * @brief + * Reweight an edge + * @param source_id + * @param target_id + * @param new_weight + */ + void Reweight(size_t source_id, size_t target_id, int new_weight) { + weights[source_id][target_id] = new_weight; + } + /** * @brief * Print the weighted graph From 3bf6e1594cb56c898860d71094f5729890533e90 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 15 Nov 2024 22:43:24 +0000 Subject: [PATCH 31/42] task_03 --- task_03/CMakeLists.txt | 4 +- task_03/src/johnson.hpp | 69 +++++++++++++++++++++++++++++++++++ task_03/src/main.cpp | 26 ++++++++++++- task_03/src/test.cpp | 67 ++++++++++++++++++++++++++++++++-- task_03/src/topology_sort.cpp | 1 - task_03/src/topology_sort.hpp | 1 - 6 files changed, 160 insertions(+), 8 deletions(-) create mode 100644 task_03/src/johnson.hpp delete mode 100644 task_03/src/topology_sort.cpp delete mode 100644 task_03/src/topology_sort.hpp diff --git a/task_03/CMakeLists.txt b/task_03/CMakeLists.txt index 7c1cb30..65417b5 100644 --- a/task_03/CMakeLists.txt +++ b/task_03/CMakeLists.txt @@ -25,7 +25,8 @@ find_package(GTest REQUIRED) include_directories(${GTEST_INCLUDE_DIRS}) find_library(Utils ../) -target_link_libraries(${PROJECT_NAME} PUBLIC Utils) +find_library(Dijkstra ../) +target_link_libraries(${PROJECT_NAME} PUBLIC Utils Dijkstra) # Link runTests with what we want to test and the GTest and pthread library add_executable(${PROJECT_NAME}_tests ${test_source_list}) @@ -33,6 +34,7 @@ target_link_libraries( ${PROJECT_NAME}_tests GTest::gtest_main Utils + Dijkstra ) include(GoogleTest) diff --git a/task_03/src/johnson.hpp b/task_03/src/johnson.hpp new file mode 100644 index 0000000..05c0c0f --- /dev/null +++ b/task_03/src/johnson.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include +#include +#include +#include + +#include "dijkstra.hpp" +#include "weighted_graph.hpp" + +constexpr int INF = std::numeric_limits::max(); + +template +std::vector> Johnson(WeightedGraph& graph) { + // Step 1: Add a new vertex + T new_vertex_data; + graph.AddVertex(new_vertex_data); + + // Step 2: Add edges from the new vertex to all other vertices with weight 0 + for (size_t u = 0; u < graph.Size() - 1; ++u) + graph.AddDirEdge(graph.Size() - 1, u, 0); + + // Step 3: Run Bellman-Ford algorithm from the new vertex + std::vector h(graph.Size(), INF); + h[graph.Size() - 1] = 0; + for (int i = 0; i < graph.Size() - 1; ++i) // |V| - 1 relaxation iterations + for (int u = 0; u < graph.Size(); ++u) + for (const auto& neighbour : graph[u]->adjacent) { + size_t v = graph.Find(neighbour->data); + if (h[u] != INF && h[u] + graph.GetWeight(u, v) < h[v]) + h[v] = h[u] + graph.GetWeight(u, v); + } + + // Step 4: Check for negative weight cycles + for (int u = 0; u < graph.Size(); ++u) + for (const auto& neighbour : graph[u]->adjacent) { + size_t v = graph.Find(neighbour->data); + if (h[u] != INF && h[u] + graph.GetWeight(u, v) < h[v]) { + std::cout << "Graph contains a negative weight cycle" << std::endl; + graph.RemoveVertex(graph.Size() - 1); + return {}; + } + } + + // Step 5: Remove the new vertex + graph.RemoveVertex(graph.Size() - 1); + + // Step 6: Reweight the edges + for (int u = 0; u < graph.Size(); ++u) + for (const auto& neighbour : graph[u]->adjacent) { + size_t v = graph.Find(neighbour->data); + if (graph.GetWeight(u, v) != INF) + graph.Reweight(u, v, graph.GetWeight(u, v) + h[u] - h[v]); + } + + // Step 7: Run Dijkstra's algorithm for each vertex + std::vector> distances(graph.Size(), + std::vector(graph.Size(), INF)); + + for (size_t u = 0; u < graph.Size(); ++u) + distances[u] = Dijkstra(graph, u).first; + + // Step 8: Restore the original weights + for (size_t u = 0; u < graph.Size(); ++u) + for (size_t v = 0; v < graph.Size(); ++v) + if (distances[u][v] != INF) distances[u][v] += h[v] - h[u]; + + return distances; +} \ No newline at end of file diff --git a/task_03/src/main.cpp b/task_03/src/main.cpp index 0e4393b..bbde365 100644 --- a/task_03/src/main.cpp +++ b/task_03/src/main.cpp @@ -1,3 +1,27 @@ #include -int main() { return 0; } +#include "johnson.hpp" + +int main() { + WeightedGraph graph; + for (int i = 0; i < 4; ++i) graph.AddVertex(i); + graph.AddDirEdge(0, 1, -5); + graph.AddDirEdge(0, 2, 2); + graph.AddDirEdge(0, 3, 3); + graph.AddDirEdge(1, 2, 4); + graph.AddDirEdge(2, 3, 1); + + std::vector> result = Johnson(graph); + + for (size_t i = 0; i < result.size(); ++i) { + std::cout << "{ "; + for (size_t j = 0; j < result[i].size(); ++j) { + if (result[i][j] != INF) + std::cout << result[i][j] << " "; + else + std::cout << "INF "; + } + std::cout << "}" << std::endl; + } + return 0; +} diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index ef5a86a..c67a093 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -1,8 +1,67 @@ - #include -#include "topology_sort.hpp" +#include "johnson.hpp" + +TEST(JohnsonAlgorithmTest, SimpleGraph) { + WeightedGraph graph; + for (int i = 0; i < 4; ++i) graph.AddVertex(i); + graph.AddDirEdge(0, 1, 1); + graph.AddDirEdge(1, 2, 2); + graph.AddDirEdge(2, 3, 1); + graph.AddDirEdge(0, 2, 4); + + std::vector> expected = { + {0, 1, 3, 4}, {INF, 0, 2, 3}, {INF, INF, 0, 1}, {INF, INF, INF, 0}}; + + std::vector> result = Johnson(graph); + EXPECT_EQ(result, expected); +} + +TEST(JohnsonAlgorithmTest, GraphWithNegativeWeights) { + WeightedGraph graph; + for (int i = 0; i < 4; ++i) graph.AddVertex(i); + graph.AddDirEdge(0, 1, -2); + graph.AddDirEdge(1, 2, -3); + graph.AddDirEdge(2, 3, 1); + graph.AddDirEdge(0, 2, 4); + + std::vector> expected = { + {0, -2, -5, -4}, {INF, 0, -3, -2}, {INF, INF, 0, 1}, {INF, INF, INF, 0}}; + + std::vector> result = Johnson(graph); + EXPECT_EQ(result, expected); +} + +TEST(JohnsonAlgorithmTest, NegativeCycle) { + WeightedGraph graph; + for (int i = 0; i < 4; ++i) graph.AddVertex(i); + graph.AddDirEdge(0, 1, 1); + graph.AddDirEdge(1, 2, 2); + graph.AddDirEdge(2, 0, -4); + graph.AddDirEdge(1, 3, 5); + + std::vector> result = Johnson(graph); + EXPECT_TRUE(result.empty()); +} -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +TEST(JohnsonAlgorithmTest, DisconnectedGraph) { + WeightedGraph graph; + for (int i = 0; i < 4; ++i) graph.AddVertex(i); + graph.AddDirEdge(0, 1, 1); + graph.AddDirEdge(1, 2, 2); + // Vertex 3 and 4 are disconnected + + std::vector> expected = { + {0, 1, 3, INF}, {INF, 0, 2, INF}, {INF, INF, 0, INF}, {INF, INF, INF, 0}}; + + std::vector> result = Johnson(graph); + EXPECT_EQ(result, expected); } + +TEST(JohnsonAlgorithmTest, EmptyGraph) { + WeightedGraph graph; + // No edges or vertices + + std::vector> result = Johnson(graph); + EXPECT_TRUE(result.empty()); +} \ No newline at end of file diff --git a/task_03/src/topology_sort.cpp b/task_03/src/topology_sort.cpp deleted file mode 100644 index e53f670..0000000 --- a/task_03/src/topology_sort.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "topology_sort.hpp" diff --git a/task_03/src/topology_sort.hpp b/task_03/src/topology_sort.hpp deleted file mode 100644 index 6f70f09..0000000 --- a/task_03/src/topology_sort.hpp +++ /dev/null @@ -1 +0,0 @@ -#pragma once From e417c491aa3e2a1e5ccb559cecb3bc0b5e0af9dd Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 18 Nov 2024 11:08:57 +0000 Subject: [PATCH 32/42] make concept usage in lib --- lib/src/graph.hpp | 37 +++++++++++++++++++++---------------- lib/src/weighted_graph.hpp | 35 ++++++++++++++++++----------------- 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 0558d7f..1b4b23a 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -16,25 +17,29 @@ struct Vertex { std::set>> adjacent; }; +template +concept IsVertex = std::derived_from>; + /// @brief Basic graph -/// @tparam T -template +/// @tparam VertexType +/// @tparam T +template requires IsVertex class Graph { public: - /** + /** * @brief * Add a new vertex to the graph * @param data */ virtual void AddVertex(const T &data) { - vertices_.push_back(std::make_shared>(data)); + vertices_.push_back(std::make_shared(data)); }; - std::shared_ptr> operator[](size_t index) { + std::shared_ptr operator[](size_t index) { return vertices_[index]; } - const std::shared_ptr> operator[](size_t index) const { + const std::shared_ptr operator[](size_t index) const { return vertices_[index]; } @@ -77,7 +82,7 @@ class Graph { * Remove a vertex from the graph * @param vertex */ - virtual void RemoveVertex(std::shared_ptr> vertex) { + virtual void RemoveVertex(std::shared_ptr vertex) { // Find the vertex in the graph auto it = std::find(vertices_.begin(), vertices_.end(), vertex); if (it == vertices_.end()) { @@ -111,8 +116,8 @@ class Graph { * @param source * @param target */ - virtual void AddDirEdge(std::shared_ptr> source, - std::shared_ptr> target) { + virtual void AddDirEdge(std::shared_ptr source, + std::shared_ptr target) { source->adjacent.insert(target); } @@ -134,8 +139,8 @@ class Graph { * @param source * @param target */ - virtual void RemoveDirEdge(std::shared_ptr> source, - std::shared_ptr> target) { + virtual void RemoveDirEdge(std::shared_ptr source, + std::shared_ptr target) { source->adjacent.erase( *std::find(source->adjacent.begin(), source->adjacent.end(), target)); } @@ -157,8 +162,8 @@ class Graph { * @param vertex_1 * @param vertex_2 */ - virtual void AddEdge(std::shared_ptr> vertex_1, - std::shared_ptr> vertex_2) { + virtual void AddEdge(std::shared_ptr vertex_1, + std::shared_ptr vertex_2) { AddDirEdge(vertex_1, vertex_2); AddDirEdge(vertex_2, vertex_1); } @@ -180,8 +185,8 @@ class Graph { * @param vertex_1 * @param vertex_2 */ - virtual void RemoveEdge(std::shared_ptr> vertex_1, - std::shared_ptr> vertex_2) { + virtual void RemoveEdge(std::shared_ptrvertex_1, + std::shared_ptr vertex_2) { RemoveDirEdge(vertex_1, vertex_2); RemoveDirEdge(vertex_2, vertex_1); } @@ -201,5 +206,5 @@ class Graph { } protected: - std::vector>> vertices_; + std::vector> vertices_; }; diff --git a/lib/src/weighted_graph.hpp b/lib/src/weighted_graph.hpp index dcea94c..feded11 100644 --- a/lib/src/weighted_graph.hpp +++ b/lib/src/weighted_graph.hpp @@ -5,13 +5,14 @@ #include "graph.hpp" /// @brief Basic weighted graph -/// @tparam T -template -class WeightedGraph : public Graph { +/// @tparam VertexType +/// @tparam T +template +class WeightedGraph : public Graph { public: - WeightedGraph() : Graph() { - weights.resize(Graph::vertices_.size(), - std::vector(Graph::vertices_.size(), + WeightedGraph() : Graph() { + weights.resize(Graph::vertices_.size(), + std::vector(Graph::vertices_.size(), std::numeric_limits::max())); } @@ -21,12 +22,12 @@ class WeightedGraph : public Graph { * @param data */ void AddVertex(const T& data) override { - Graph::AddVertex(data); - weights.resize(Graph::vertices_.size(), - std::vector(Graph::vertices_.size(), + Graph::AddVertex(data); + weights.resize(Graph::vertices_.size(), + std::vector(Graph::vertices_.size(), std::numeric_limits::max())); for (auto& row : weights) - row.resize(Graph::vertices_.size(), std::numeric_limits::max()); + row.resize(Graph::vertices_.size(), std::numeric_limits::max()); } /** @@ -36,7 +37,7 @@ class WeightedGraph : public Graph { */ void RemoveVertex(size_t vertex_id) override { // Remove the vertex from the base class - Graph::RemoveVertex(vertex_id); + Graph::RemoveVertex(vertex_id); // Remove the corresponding row and column from the weights matrix weights.erase(weights.begin() + vertex_id); // Remove the row @@ -53,7 +54,7 @@ class WeightedGraph : public Graph { * @param weight */ void AddDirEdge(size_t source_id, size_t target_id, int weight) { - Graph::AddDirEdge(source_id, target_id); + Graph::AddDirEdge(source_id, target_id); weights[source_id][target_id] = weight; } @@ -76,7 +77,7 @@ class WeightedGraph : public Graph { * @param target_id */ void RemoveDirEdge(size_t source_id, size_t target_id) override { - Graph::RemoveDirEdge(source_id, target_id); + Graph::RemoveDirEdge(source_id, target_id); weights[source_id][target_id] = std::numeric_limits::max(); } @@ -118,10 +119,10 @@ class WeightedGraph : public Graph { * Print the weighted graph */ void PrintGraph() const override { - for (size_t i = 0; i < Graph::vertices_.size(); ++i) { - std::cout << Graph::vertices_[i]->data << " -> "; - for (const auto& neighbor : Graph::vertices_[i]->adjacent) { - size_t j = Graph::Find(neighbor->data); + for (size_t i = 0; i < Graph::vertices_.size(); ++i) { + std::cout << Graph::vertices_[i]->data << " -> "; + for (const auto& neighbor : Graph::vertices_[i]->adjacent) { + size_t j = Graph::Find(neighbor->data); std::cout << "(" << neighbor->data << ", " << weights[i][j] << ") "; } std::cout << std::endl; From a1bdefff245c2a4cf7c97f00c68ea9f8d4a274f4 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 18 Nov 2024 11:09:27 +0000 Subject: [PATCH 33/42] rewrite tasks due to lib changes --- task_01/src/packman.cpp | 4 ++-- task_01/src/packman.hpp | 12 +++++++++--- task_02/src/network.hpp | 9 ++++++++- task_03/src/johnson.hpp | 5 ++--- task_03/src/main.cpp | 2 +- task_03/src/test.cpp | 10 +++++----- task_04/src/dijkstra.hpp | 4 ++-- task_04/src/test.cpp | 6 +++--- 8 files changed, 32 insertions(+), 20 deletions(-) diff --git a/task_01/src/packman.cpp b/task_01/src/packman.cpp index acb326d..5423611 100644 --- a/task_01/src/packman.cpp +++ b/task_01/src/packman.cpp @@ -1,7 +1,7 @@ #include "packman.hpp" void PackageManager::FindingOrderStep( - std::shared_ptr> target) { + std::shared_ptr target) { is_visited_[dependencies_.Find(target->data)] = true; for (auto& neighbor : target->adjacent) { @@ -14,7 +14,7 @@ void PackageManager::FindingOrderStep( } std::vector PackageManager::FindDownloadingOrder(/* - std::shared_ptr> target*/) { + std::shared_ptr target*/) { is_visited_.resize(dependencies_.Size()); for (size_t i = 0; i < is_visited_.size(); ++i) is_visited_[i] = false; diff --git a/task_01/src/packman.hpp b/task_01/src/packman.hpp index 4fbea16..f7e5247 100644 --- a/task_01/src/packman.hpp +++ b/task_01/src/packman.hpp @@ -5,9 +5,15 @@ #include "graph.hpp" +/// @brief Vertex representing single downloadable package +class Library : public Vertex{ + public: + std::set> adjacent; +}; + /// @brief Graph of dependencies between libraries /// The "parent" libraries should be installed before thier children -class DependencyGraph : public Graph {}; +class DependencyGraph : public Graph {}; /// @brief Packman basic algorithm class PackageManager { @@ -23,10 +29,10 @@ class PackageManager { * @return std::vector */ std::vector FindDownloadingOrder(/* - std::shared_ptr> target*/); + std::shared_ptr target*/); private: - void FindingOrderStep(std::shared_ptr> target); + void FindingOrderStep(std::shared_ptr target); DependencyGraph& dependencies_; std::vector is_visited_; std::stack reverse_order_; diff --git a/task_02/src/network.hpp b/task_02/src/network.hpp index 7e36cca..f221ddf 100644 --- a/task_02/src/network.hpp +++ b/task_02/src/network.hpp @@ -2,8 +2,15 @@ #include "graph.hpp" +/// @brief Vertex representing a single router +class Router : public Vertex{ + public: + std::set> adjacent; +}; + + /// @brief Graph of routers in cities net -class Network : public Graph { +class Network : public Graph { public: /// @brief Finds bridges and cut vertices in graph using Tarjan's algorithm std::pair>, std::vector> diff --git a/task_03/src/johnson.hpp b/task_03/src/johnson.hpp index 05c0c0f..721d725 100644 --- a/task_03/src/johnson.hpp +++ b/task_03/src/johnson.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -10,8 +9,8 @@ constexpr int INF = std::numeric_limits::max(); -template -std::vector> Johnson(WeightedGraph& graph) { +template +std::vector> Johnson(WeightedGraph& graph) { // Step 1: Add a new vertex T new_vertex_data; graph.AddVertex(new_vertex_data); diff --git a/task_03/src/main.cpp b/task_03/src/main.cpp index bbde365..f1f37f4 100644 --- a/task_03/src/main.cpp +++ b/task_03/src/main.cpp @@ -3,7 +3,7 @@ #include "johnson.hpp" int main() { - WeightedGraph graph; + WeightedGraph,int> graph; for (int i = 0; i < 4; ++i) graph.AddVertex(i); graph.AddDirEdge(0, 1, -5); graph.AddDirEdge(0, 2, 2); diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index c67a093..f436a7a 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -3,7 +3,7 @@ #include "johnson.hpp" TEST(JohnsonAlgorithmTest, SimpleGraph) { - WeightedGraph graph; + WeightedGraph, int> graph; for (int i = 0; i < 4; ++i) graph.AddVertex(i); graph.AddDirEdge(0, 1, 1); graph.AddDirEdge(1, 2, 2); @@ -18,7 +18,7 @@ TEST(JohnsonAlgorithmTest, SimpleGraph) { } TEST(JohnsonAlgorithmTest, GraphWithNegativeWeights) { - WeightedGraph graph; + WeightedGraph, int> graph; for (int i = 0; i < 4; ++i) graph.AddVertex(i); graph.AddDirEdge(0, 1, -2); graph.AddDirEdge(1, 2, -3); @@ -33,7 +33,7 @@ TEST(JohnsonAlgorithmTest, GraphWithNegativeWeights) { } TEST(JohnsonAlgorithmTest, NegativeCycle) { - WeightedGraph graph; + WeightedGraph, int> graph; for (int i = 0; i < 4; ++i) graph.AddVertex(i); graph.AddDirEdge(0, 1, 1); graph.AddDirEdge(1, 2, 2); @@ -45,7 +45,7 @@ TEST(JohnsonAlgorithmTest, NegativeCycle) { } TEST(JohnsonAlgorithmTest, DisconnectedGraph) { - WeightedGraph graph; + WeightedGraph, int> graph; for (int i = 0; i < 4; ++i) graph.AddVertex(i); graph.AddDirEdge(0, 1, 1); graph.AddDirEdge(1, 2, 2); @@ -59,7 +59,7 @@ TEST(JohnsonAlgorithmTest, DisconnectedGraph) { } TEST(JohnsonAlgorithmTest, EmptyGraph) { - WeightedGraph graph; + WeightedGraph, int> graph; // No edges or vertices std::vector> result = Johnson(graph); diff --git a/task_04/src/dijkstra.hpp b/task_04/src/dijkstra.hpp index c538f40..9cd2178 100644 --- a/task_04/src/dijkstra.hpp +++ b/task_04/src/dijkstra.hpp @@ -3,9 +3,9 @@ #include "weighted_graph.hpp" -template +template std::pair, std::vector> Dijkstra( - const WeightedGraph& graph, size_t start) { + const WeightedGraph& graph, size_t start) { const size_t size = graph.Size(); // Distance array to store shortest distances from start diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 9fc4a27..c89c443 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -17,7 +17,7 @@ void CheckPaths(std::vector& prev, } TEST(DijkstraTest, SimpleUndirectedGraph) { - WeightedGraph graph; + WeightedGraph, int> graph; // Add vertices for (int i = 0; i < 5; i++) graph.AddVertex(i); @@ -46,7 +46,7 @@ TEST(DijkstraTest, SimpleUndirectedGraph) { } TEST(DijkstraTest, SimpleDirectedGraph) { - WeightedGraph graph; + WeightedGraph, int> graph; // Add vertices for (int i = 0; i < 5; i++) graph.AddVertex(i); @@ -75,7 +75,7 @@ TEST(DijkstraTest, SimpleDirectedGraph) { } TEST(DijkstraTest, DisconnectedGraph) { - WeightedGraph graph; + WeightedGraph, int> graph; // Add vertices for (int i = 0; i < 3; i++) graph.AddVertex(i); From 1375f5d85f82134d80b9e1e53da064f9927b9af8 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 18 Nov 2024 11:16:45 +0000 Subject: [PATCH 34/42] format changes --- lib/src/graph.hpp | 13 +++++++------ lib/src/weighted_graph.hpp | 16 +++++++++------- task_01/src/packman.cpp | 3 +-- task_01/src/packman.hpp | 4 ++-- task_02/src/network.hpp | 5 ++--- task_03/src/main.cpp | 2 +- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 1b4b23a..97cf7db 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -17,16 +17,17 @@ struct Vertex { std::set>> adjacent; }; -template +template concept IsVertex = std::derived_from>; /// @brief Basic graph -/// @tparam VertexType -/// @tparam T -template requires IsVertex +/// @tparam VertexType +/// @tparam T +template + requires IsVertex class Graph { public: - /** + /** * @brief * Add a new vertex to the graph * @param data @@ -185,7 +186,7 @@ class Graph { * @param vertex_1 * @param vertex_2 */ - virtual void RemoveEdge(std::shared_ptrvertex_1, + virtual void RemoveEdge(std::shared_ptr vertex_1, std::shared_ptr vertex_2) { RemoveDirEdge(vertex_1, vertex_2); RemoveDirEdge(vertex_2, vertex_1); diff --git a/lib/src/weighted_graph.hpp b/lib/src/weighted_graph.hpp index feded11..680230f 100644 --- a/lib/src/weighted_graph.hpp +++ b/lib/src/weighted_graph.hpp @@ -5,14 +5,14 @@ #include "graph.hpp" /// @brief Basic weighted graph -/// @tparam VertexType -/// @tparam T +/// @tparam VertexType +/// @tparam T template class WeightedGraph : public Graph { public: - WeightedGraph() : Graph() { - weights.resize(Graph::vertices_.size(), - std::vector(Graph::vertices_.size(), + WeightedGraph() : Graph() { + weights.resize(Graph::vertices_.size(), + std::vector(Graph::vertices_.size(), std::numeric_limits::max())); } @@ -27,7 +27,8 @@ class WeightedGraph : public Graph { std::vector(Graph::vertices_.size(), std::numeric_limits::max())); for (auto& row : weights) - row.resize(Graph::vertices_.size(), std::numeric_limits::max()); + row.resize(Graph::vertices_.size(), + std::numeric_limits::max()); } /** @@ -121,7 +122,8 @@ class WeightedGraph : public Graph { void PrintGraph() const override { for (size_t i = 0; i < Graph::vertices_.size(); ++i) { std::cout << Graph::vertices_[i]->data << " -> "; - for (const auto& neighbor : Graph::vertices_[i]->adjacent) { + for (const auto& neighbor : + Graph::vertices_[i]->adjacent) { size_t j = Graph::Find(neighbor->data); std::cout << "(" << neighbor->data << ", " << weights[i][j] << ") "; } diff --git a/task_01/src/packman.cpp b/task_01/src/packman.cpp index 5423611..7a2c5e8 100644 --- a/task_01/src/packman.cpp +++ b/task_01/src/packman.cpp @@ -1,7 +1,6 @@ #include "packman.hpp" -void PackageManager::FindingOrderStep( - std::shared_ptr target) { +void PackageManager::FindingOrderStep(std::shared_ptr target) { is_visited_[dependencies_.Find(target->data)] = true; for (auto& neighbor : target->adjacent) { diff --git a/task_01/src/packman.hpp b/task_01/src/packman.hpp index f7e5247..bf92f4c 100644 --- a/task_01/src/packman.hpp +++ b/task_01/src/packman.hpp @@ -6,8 +6,8 @@ #include "graph.hpp" /// @brief Vertex representing single downloadable package -class Library : public Vertex{ - public: +class Library : public Vertex { + public: std::set> adjacent; }; diff --git a/task_02/src/network.hpp b/task_02/src/network.hpp index f221ddf..e538d8b 100644 --- a/task_02/src/network.hpp +++ b/task_02/src/network.hpp @@ -3,12 +3,11 @@ #include "graph.hpp" /// @brief Vertex representing a single router -class Router : public Vertex{ - public: +class Router : public Vertex { + public: std::set> adjacent; }; - /// @brief Graph of routers in cities net class Network : public Graph { public: diff --git a/task_03/src/main.cpp b/task_03/src/main.cpp index f1f37f4..09ffeca 100644 --- a/task_03/src/main.cpp +++ b/task_03/src/main.cpp @@ -3,7 +3,7 @@ #include "johnson.hpp" int main() { - WeightedGraph,int> graph; + WeightedGraph, int> graph; for (int i = 0; i < 4; ++i) graph.AddVertex(i); graph.AddDirEdge(0, 1, -5); graph.AddDirEdge(0, 2, 2); From c3f6de7ae1b4fc07cdd53930105e1480d1668a87 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 18 Nov 2024 23:43:18 +0000 Subject: [PATCH 35/42] weaken graph concept --- lib/src/graph.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 97cf7db..f184d4a 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -1,10 +1,10 @@ #pragma once #include -#include #include #include #include +#include #include /// @brief Graphs vertex @@ -18,7 +18,7 @@ struct Vertex { }; template -concept IsVertex = std::derived_from>; +concept IsVertex = std::is_base_of, T>::value; /// @brief Basic graph /// @tparam VertexType From 1ea4514f82c55c882fe92b1be5f5330cb1de3e3b Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 29 Nov 2024 12:24:30 +0000 Subject: [PATCH 36/42] task_01 adapted to package manager simulating --- task_01/src/main.cpp | 28 ++++---- task_01/src/packman.cpp | 31 ++++----- task_01/src/packman.hpp | 9 ++- task_01/src/test.cpp | 142 ++++++++++++++++++---------------------- 4 files changed, 100 insertions(+), 110 deletions(-) diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp index 96f74c4..48a53f6 100644 --- a/task_01/src/main.cpp +++ b/task_01/src/main.cpp @@ -1,23 +1,25 @@ #include "packman.hpp" int main() { - DependencyGraph dg_1; + DependencyGraph dg; - dg_1.AddVertex("Lib_1"); - dg_1.AddVertex("Lib_2"); - dg_1.AddVertex("Lib_3"); - dg_1.AddVertex("Lib_4"); - dg_1.AddVertex("Lib_5"); + std::vector packages = {"Lib_1", "Lib_2", "Lib_3", "Lib_4", + "Lib_5"}; + for (const auto& package : packages) dg.AddVertex(package); - dg_1.AddDirEdge(0, 1); - dg_1.AddDirEdge(0, 2); - dg_1.AddDirEdge(2, 3); - dg_1.AddDirEdge(3, 1); - dg_1.AddDirEdge(0, 3); + dg.AddDirEdge(0, 1); // Lib_1 depends on Lib_2 + dg.AddDirEdge(0, 2); // Lib_1 depends on Lib_3 + dg.AddDirEdge(2, 3); // Lib_3 depends on Lib_4 + dg.AddDirEdge(3, 1); // Lib_4 depends on Lib_2 + dg.AddDirEdge(0, 3); // Lib_1 depends on Lib_4 - PackageManager packman_1(dg_1); + PackageManager packman(dg); - packman_1.FindDownloadingOrder(); + packman.FindDownloadingOrder("Lib_1"); + packman.FindDownloadingOrder("Lib_2"); + packman.FindDownloadingOrder("Lib_3"); + packman.FindDownloadingOrder("Lib_4"); + packman.FindDownloadingOrder("Lib_5"); return 0; } diff --git a/task_01/src/packman.cpp b/task_01/src/packman.cpp index 7a2c5e8..6566dba 100644 --- a/task_01/src/packman.cpp +++ b/task_01/src/packman.cpp @@ -3,31 +3,32 @@ void PackageManager::FindingOrderStep(std::shared_ptr target) { is_visited_[dependencies_.Find(target->data)] = true; - for (auto& neighbor : target->adjacent) { - if (!is_visited_[dependencies_.Find(neighbor->data)]) { + for (auto& neighbor : target->adjacent) + if (!is_visited_[dependencies_.Find(neighbor->data)]) FindingOrderStep(neighbor); - } - } - reverse_order_.push(target->data); + order_.push(target->data); } -std::vector PackageManager::FindDownloadingOrder(/* - std::shared_ptr target*/) { +std::vector PackageManager::FindDownloadingOrder( + std::string target) { + std::size_t target_id = dependencies_.Find(target); + if (target_id == dependencies_.Size()) { + std::cout << "No such package : " << target << std::endl; + return {}; + } is_visited_.resize(dependencies_.Size()); for (size_t i = 0; i < is_visited_.size(); ++i) is_visited_[i] = false; - for (size_t i = 0; i < dependencies_.Size(); ++i) - if (!is_visited_[i]) FindingOrderStep(dependencies_[i]); + FindingOrderStep(dependencies_[target_id]); std::vector order; - std::cout << "Downloading Order for " - << /*target->data <<*/ " is:" << std::endl; - while (reverse_order_.size() > 0) { - order.push_back(reverse_order_.top()); - std::cout << reverse_order_.top() << " "; - reverse_order_.pop(); + std::cout << "Downloading Order for " << target << " is :" << std::endl; + while (order_.size() > 0) { + order.push_back(order_.front()); + std::cout << order_.front() << " "; + order_.pop(); } std::cout << std::endl; return order; diff --git a/task_01/src/packman.hpp b/task_01/src/packman.hpp index bf92f4c..3394a6c 100644 --- a/task_01/src/packman.hpp +++ b/task_01/src/packman.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include "graph.hpp" @@ -12,7 +12,7 @@ class Library : public Vertex { }; /// @brief Graph of dependencies between libraries -/// The "parent" libraries should be installed before thier children +/// The "parent" libraries should be installed after thier children class DependencyGraph : public Graph {}; /// @brief Packman basic algorithm @@ -28,12 +28,11 @@ class PackageManager { * @param target Needed library * @return std::vector */ - std::vector FindDownloadingOrder(/* - std::shared_ptr target*/); + std::vector FindDownloadingOrder(std::string target); private: void FindingOrderStep(std::shared_ptr target); DependencyGraph& dependencies_; std::vector is_visited_; - std::stack reverse_order_; + std::queue order_; }; \ No newline at end of file diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index b56d7bb..7df7106 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -4,108 +4,96 @@ TEST(Test, Example_1) { // Example 1: Small graph - DependencyGraph dg_1; + DependencyGraph dg; + std::vector packages = {"Basic_Package", "Extention"}; + for (const auto& package : packages) dg.AddVertex(package); - dg_1.AddVertex("Basic_Package"); - dg_1.AddVertex("Extention"); + dg.AddDirEdge(1, 0); - dg_1.AddDirEdge(0, 1); + PackageManager packman(dg); - PackageManager packman_1(dg_1); + std::vector> answers{{"Basic_Package"}, + {"Basic_Package", "Extention"}}; - // std::vector> answers{{"Basic_Package"}, - // {"Basic_Package", "Extention"}}; - - std::vector answer{"Basic_Package", "Extention"}; - - ASSERT_EQ(answer, packman_1.FindDownloadingOrder()); + for (size_t i = 0; i < answers.size(); ++i) + ASSERT_EQ(answers[i], packman.FindDownloadingOrder(packages[i])); } - TEST(Test, Example_2) { // Example 2: Three vertices, one edge - DependencyGraph dg_2; + DependencyGraph dg; - dg_2.AddVertex("First"); - dg_2.AddVertex("Second"); - dg_2.AddVertex("Independent"); + std::vector packages = {"First", "Second", "Independent"}; - dg_2.AddDirEdge(0, 1); + for (const auto& package : packages) dg.AddVertex(package); - PackageManager packman_2(dg_2); + dg.AddDirEdge(1, 0); - // std::vector> answers{ - // {"First"}, {"First", "Second"}, {"Independent"}}; + PackageManager packman(dg); - std::vector answer{{"Independent", "First", "Second"}}; + std::vector> answers{ + {"First"}, {"First", "Second"}, {"Independent"}}; - ASSERT_EQ(answer, packman_2.FindDownloadingOrder()); + for (size_t i = 0; i < answers.size(); ++i) + ASSERT_EQ(answers[i], packman.FindDownloadingOrder(packages[i])); } TEST(Test, Example_3) { // Example 3: Five vertices, more complex dependencies - DependencyGraph dg_3; + DependencyGraph dg; - dg_3.AddVertex("BaseLib"); - dg_3.AddVertex("TestLib"); - dg_3.AddVertex("DataLib"); - dg_3.AddVertex("AlgorithmLib"); - dg_3.AddVertex("ToolLib"); + std::vector packages = {"BaseLib", "TestLib", "DataLib", + "AlgorithmLib", "ToolLib"}; - dg_3.AddDirEdge(0, 1); - dg_3.AddDirEdge(0, 2); - dg_3.AddDirEdge(2, 3); - dg_3.AddDirEdge(3, 4); + for (const auto& package : packages) dg.AddVertex(package); - PackageManager packman_3(dg_3); + dg.AddDirEdge(1, 0); + dg.AddDirEdge(2, 0); + dg.AddDirEdge(3, 2); + dg.AddDirEdge(4, 3); - // std::vector> answers{ - // {"BaseLib"}, - // {"BaseLib", "TestLib"}, - // {"BaseLib", "DataLib"}, - // {"BaseLib", "DataLib", "AlgorithmLib"}, - // {"BaseLib", "DataLib", "AlgorithmLib", "ToolLib"}}; + PackageManager packman(dg); - std::vector answer{"BaseLib", "DataLib", "AlgorithmLib", - "ToolLib", "TestLib"}; + std::vector> answers{ + {"BaseLib"}, + {"BaseLib", "TestLib"}, + {"BaseLib", "DataLib"}, + {"BaseLib", "DataLib", "AlgorithmLib"}, + {"BaseLib", "DataLib", "AlgorithmLib", "ToolLib"}}; - ASSERT_EQ(answer, packman_3.FindDownloadingOrder()); + for (size_t i = 0; i < answers.size(); ++i) + ASSERT_EQ(answers[i], packman.FindDownloadingOrder(packages[i])); } TEST(Test, Example_4) { // Example 4: More complex graph, multiple paths - DependencyGraph dg_4; - - dg_4.AddVertex("Start"); - dg_4.AddVertex("A1"); - dg_4.AddVertex("A2"); - dg_4.AddVertex("B1"); - dg_4.AddVertex("B2"); - dg_4.AddVertex("C1"); - dg_4.AddVertex("C2"); - dg_4.AddVertex("End"); - - dg_4.AddDirEdge(0, 1); - dg_4.AddDirEdge(0, 2); - dg_4.AddDirEdge(1, 3); - dg_4.AddDirEdge(2, 4); - dg_4.AddDirEdge(3, 5); - dg_4.AddDirEdge(4, 6); - dg_4.AddDirEdge(5, 7); - dg_4.AddDirEdge(6, 7); - PackageManager packman_4(dg_4); - - // std::vector> answers{ - // {"Start"}, - // {"Start", "A1"}, - // {"Start", "A2"}, - // {"Start", "A1", "B1"}, - // {"Start", "A2", "B2"}, - // {"Start", "A1", "B1", "C1"}, - // {"Start", "A2", "B2", "C2"}, - // {"Start", "A1", "B1", "C1", "A2", "B2", "C2", "End"}}; - - std::vector answer{"Start", "A1", "B1", "C1", - "A2", "B2", "C2", "End"}; - - ASSERT_EQ(answer, packman_4.FindDownloadingOrder()); + DependencyGraph dg; + + std::vector packages = {"Start", "A1", "A2", "B1", + "B2", "C1", "C2", "End"}; + + for (const auto& package : packages) dg.AddVertex(package); + + dg.AddDirEdge(1, 0); + dg.AddDirEdge(2, 0); + dg.AddDirEdge(3, 1); + dg.AddDirEdge(4, 2); + dg.AddDirEdge(5, 3); + dg.AddDirEdge(6, 4); + dg.AddDirEdge(7, 5); + dg.AddDirEdge(7, 6); + + PackageManager packman(dg); + + std::vector> answers{ + {"Start"}, + {"Start", "A1"}, + {"Start", "A2"}, + {"Start", "A1", "B1"}, + {"Start", "A2", "B2"}, + {"Start", "A1", "B1", "C1"}, + {"Start", "A2", "B2", "C2"}, + {"Start", "A1", "B1", "C1", "A2", "B2", "C2", "End"}}; + + for (size_t i = 0; i < answers.size(); ++i) + ASSERT_EQ(answers[i], packman.FindDownloadingOrder(packages[i])); } \ No newline at end of file From 89105a39ad22a0362903ceae8f2493f619eaacad Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 29 Nov 2024 14:05:16 +0000 Subject: [PATCH 37/42] add check if graph is cyclic --- task_01/src/packman.cpp | 35 +++++++++++++++++++++++++++++++++++ task_01/src/packman.hpp | 3 +++ task_01/src/test.cpp | 1 + 3 files changed, 39 insertions(+) diff --git a/task_01/src/packman.cpp b/task_01/src/packman.cpp index 6566dba..7c453b7 100644 --- a/task_01/src/packman.cpp +++ b/task_01/src/packman.cpp @@ -1,5 +1,33 @@ #include "packman.hpp" +bool PackageManager::IsCyclicUtil(std::shared_ptr node, + std::vector& visited, + std::vector& recStack) { + if (!visited[dependencies_.Find(node->data)]) { + visited[dependencies_.Find(node->data)] = true; + recStack[dependencies_.Find(node->data)] = true; + + for (auto& neighbor : node->adjacent) + if (!visited[dependencies_.Find(neighbor->data)] && + IsCyclicUtil(neighbor, visited, recStack)) + return true; + else if (recStack[dependencies_.Find(neighbor->data)]) + return true; + } + recStack[dependencies_.Find(node->data)] = false; + return false; +} + +bool PackageManager::IsCyclic() { + std::vector visited(dependencies_.Size(), false); + std::vector recStack(dependencies_.Size(), false); + + for (std::size_t i = 0; i < dependencies_.Size(); ++i) + if (IsCyclicUtil(dependencies_[i], visited, recStack)) return true; + + return false; +} + void PackageManager::FindingOrderStep(std::shared_ptr target) { is_visited_[dependencies_.Find(target->data)] = true; @@ -12,11 +40,18 @@ void PackageManager::FindingOrderStep(std::shared_ptr target) { std::vector PackageManager::FindDownloadingOrder( std::string target) { + if (IsCyclic()) { + std::cout << "The graph is cyclic. Downloading order is undetermined." + << std::endl; + return {}; + } + std::size_t target_id = dependencies_.Find(target); if (target_id == dependencies_.Size()) { std::cout << "No such package : " << target << std::endl; return {}; } + is_visited_.resize(dependencies_.Size()); for (size_t i = 0; i < is_visited_.size(); ++i) is_visited_[i] = false; diff --git a/task_01/src/packman.hpp b/task_01/src/packman.hpp index 3394a6c..3120a1e 100644 --- a/task_01/src/packman.hpp +++ b/task_01/src/packman.hpp @@ -31,6 +31,9 @@ class PackageManager { std::vector FindDownloadingOrder(std::string target); private: + bool IsCyclicUtil(std::shared_ptr node, std::vector& visited, + std::vector& recStack); + bool IsCyclic(); void FindingOrderStep(std::shared_ptr target); DependencyGraph& dependencies_; std::vector is_visited_; diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 7df7106..09492f3 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -18,6 +18,7 @@ TEST(Test, Example_1) { for (size_t i = 0; i < answers.size(); ++i) ASSERT_EQ(answers[i], packman.FindDownloadingOrder(packages[i])); } + TEST(Test, Example_2) { // Example 2: Three vertices, one edge DependencyGraph dg; From 238a5a3f916446a2060f603ed6295c3e975053e9 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 1 Dec 2024 15:34:43 +0000 Subject: [PATCH 38/42] add task description --- additional_tasks/merge_users/README.md | 19 +++++++++++++++++++ additional_tasks/template_task/README.md | 3 --- 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 additional_tasks/merge_users/README.md delete mode 100644 additional_tasks/template_task/README.md diff --git a/additional_tasks/merge_users/README.md b/additional_tasks/merge_users/README.md new file mode 100644 index 0000000..0fc3b98 --- /dev/null +++ b/additional_tasks/merge_users/README.md @@ -0,0 +1,19 @@ +# Users merge + +There are n users, each of them corresponds to a list of emails (total m emails). For example: +user1 -> xxx@ya.ru, foo@gmail.com, lol@mail.ru +user2 -> foo@gmail.com, ups@pisem.net +user3 -> xyz@pisem.net, vasya@pupkin.com +user4 -> ups@pisem.net, aaa@bbb.ru +user5 -> xyz@pisem.net + +It is assumed that if two users have a common email, then they are the same user. + +We need to build and implement an algorithm that merges users. The output should be a list of users with their email addresses (the same as the input). + +In the above example, the answer to the task would be as follows: +user1 -> xxx@ya.ru, foo@gmail.com, lol@mail.ru, ups@pisem.net, aaa@bbb.ru +user3 -> xyz@pisem.net, vasya@pupkin.com + + +Translated with DeepL.com (free version) \ No newline at end of file diff --git a/additional_tasks/template_task/README.md b/additional_tasks/template_task/README.md deleted file mode 100644 index 8e59f99..0000000 --- a/additional_tasks/template_task/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Шаблонная задача - -Описание задачи \ No newline at end of file From a91e0b3f88dc6b5c44ece5743837a44de0c48530 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 1 Dec 2024 15:35:01 +0000 Subject: [PATCH 39/42] task solution --- .../CMakeLists.txt | 0 additional_tasks/merge_users/src/main.cpp | 17 +++ .../merge_users/src/merge_users.cpp | 63 ++++++++ .../merge_users/src/merge_users.hpp | 55 +++++++ additional_tasks/merge_users/src/test.cpp | 144 ++++++++++++++++++ additional_tasks/template_task/src/main.cpp | 1 - additional_tasks/template_task/src/test.cpp | 8 - additional_tasks/template_task/src/utils.cpp | 1 - additional_tasks/template_task/src/utils.hpp | 1 - 9 files changed, 279 insertions(+), 11 deletions(-) rename additional_tasks/{template_task => merge_users}/CMakeLists.txt (100%) create mode 100644 additional_tasks/merge_users/src/main.cpp create mode 100644 additional_tasks/merge_users/src/merge_users.cpp create mode 100644 additional_tasks/merge_users/src/merge_users.hpp create mode 100644 additional_tasks/merge_users/src/test.cpp delete mode 100644 additional_tasks/template_task/src/main.cpp delete mode 100644 additional_tasks/template_task/src/test.cpp delete mode 100644 additional_tasks/template_task/src/utils.cpp delete mode 100644 additional_tasks/template_task/src/utils.hpp diff --git a/additional_tasks/template_task/CMakeLists.txt b/additional_tasks/merge_users/CMakeLists.txt similarity index 100% rename from additional_tasks/template_task/CMakeLists.txt rename to additional_tasks/merge_users/CMakeLists.txt diff --git a/additional_tasks/merge_users/src/main.cpp b/additional_tasks/merge_users/src/main.cpp new file mode 100644 index 0000000..8ff6e26 --- /dev/null +++ b/additional_tasks/merge_users/src/main.cpp @@ -0,0 +1,17 @@ +#include "merge_users.hpp" + +int main() { + std::vector users = { + User("user1", {"xxx@ya.ru", "foo@gmail.com", "lol@mail.ru"}), + User("user2", {"foo@gmail.com", "ups@pisem.net"}), + User("user3", {"xyz@pisem.net", "vasya@pupkin.com"}), + User("user4", {"ups@pisem.net", "aaa@bbb.ru"}), + User("user5", {"xyz@pisem.net"})}; + + std::vector merged_users = MergeUsers(users); + + // Print the merged users and their emails + for (const auto& user : merged_users) std::cout << user << std::endl; + + return 0; +} \ No newline at end of file diff --git a/additional_tasks/merge_users/src/merge_users.cpp b/additional_tasks/merge_users/src/merge_users.cpp new file mode 100644 index 0000000..845a184 --- /dev/null +++ b/additional_tasks/merge_users/src/merge_users.cpp @@ -0,0 +1,63 @@ +#include "merge_users.hpp" + +std::vector DFSMergeUtil(const Graph, UserData>& graph, + std::map& node_index) { + std::vector visited(graph.Size(), false); + std::vector merged_users; + + for (std::size_t i = 0; i < graph.Size(); ++i) + if (!visited[i]) { + std::set names; + std::set emails; + std::stack stack; + stack.push(i); + visited[i] = true; + + while (!stack.empty()) { + std::size_t u = stack.top(); + stack.pop(); + UserData node = graph[u]->data; + + if (node.type == Type::Name) + names.insert(node.data); + else + emails.insert(node.data); + + for (const auto& neighbor : graph[u]->adjacent) { + int v = node_index[neighbor->data.data]; + if (!visited[v]) { + visited[v] = true; + stack.push(v); + } + } + } + // Take the first user as representative + if (!names.empty()) merged_users.push_back(User(*names.cbegin(), emails)); + } + return merged_users; +} + +std::vector MergeUsers(std::vector& users) { + // Create a graph + Graph, UserData> graph; + + // Create a map to store the index of each node (string to integer) + std::map node_index; + + // Add vertices to the graph + for (const auto& user : users) { + if (node_index.find(user.name) == node_index.end()) { + node_index[user.name] = graph.Size(); + graph.AddVertex(UserData(user.name, Type::Name)); + } + for (const std::string& email : user.emails) { + if (node_index.find(email) == node_index.end()) { + node_index[email] = graph.Size(); + graph.AddVertex(UserData(email, Type::Email)); + } + graph.AddEdge(node_index[user.name], node_index[email]); + } + } + std::vector merged_users = DFSMergeUtil(graph, node_index); + return merged_users; +} diff --git a/additional_tasks/merge_users/src/merge_users.hpp b/additional_tasks/merge_users/src/merge_users.hpp new file mode 100644 index 0000000..e6d635e --- /dev/null +++ b/additional_tasks/merge_users/src/merge_users.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "graph.hpp" + +/// @brief Type of user data +enum Type { Name, Email }; + +/// @brief User data +struct UserData { + UserData(const std::string& data, Type type) : data(data), type(type) {} + std::string data; + Type type; +}; + +inline std::ostream& operator<<(std::ostream& os, const UserData& u_data) { + os << u_data.data; + return os; +} + +/// @brief User with a name and email +struct User { + User(const std::string& name, const std::set& emails) + : name(name), emails(emails) {} + std::string name; + std::set emails; // set to avoid duplicates +}; + +inline std::ostream& operator<<(std::ostream& os, const User& u) { + os << u.name << " -> "; + for (const std::string& email : u.emails) os << email << " "; + return os; +} + +inline bool operator==(const User& fu, const User& su) { + return fu.name == su.name && fu.emails == su.emails; +} + +/// @brief Perform Depth-First Search (DFS) to find connected components +/// @param graph : The graph to search +/// @param node_index : Quick access form data to index +/// @return Contatiner of merged users +std::vector DFSMergeUtil(const Graph, UserData>& graph, + std::map& node_index); + +/// @brief Merge users with matching emails +/// @param users : The list of users to merge +/// @return Merged users +std::vector MergeUsers(std::vector& users); \ No newline at end of file diff --git a/additional_tasks/merge_users/src/test.cpp b/additional_tasks/merge_users/src/test.cpp new file mode 100644 index 0000000..7d2db9d --- /dev/null +++ b/additional_tasks/merge_users/src/test.cpp @@ -0,0 +1,144 @@ +#include + +#include "merge_users.hpp" + +// Test case to check merging of users with overlapping emails +TEST(MergeUsersTest, OverlappingEmails) { + std::vector users = { + User("user1", {"email1@example.com", "email2@example.com"}), + User("user2", {"email2@example.com", "email3@example.com"}), + User("user3", {"email4@example.com"})}; + + std::vector except_merge = { + User("user1", + {"email1@example.com", "email2@example.com", "email3@example.com"}), + User("user3", {"email4@example.com"})}; + + std::vector merged_users = MergeUsers(users); + + EXPECT_EQ(merged_users.size(), except_merge.size()); + for (size_t i = 0; i < merged_users.size(); ++i) + EXPECT_EQ(merged_users[i], except_merge[i]); +} + +// Test case to check merging of users with no overlapping emails +TEST(MergeUsersTest, NoOverlappingEmails) { + std::vector users = {User("user1", {"email1@example.com"}), + User("user2", {"email2@example.com"}), + User("user3", {"email3@example.com"})}; + + std::vector except_merge = users; + + std::vector merged_users = MergeUsers(users); + + EXPECT_EQ(merged_users.size(), except_merge.size()); + for (size_t i = 0; i < merged_users.size(); ++i) + EXPECT_EQ(merged_users[i], except_merge[i]); +} + +// Test case to check merging of users with multiple names and emails +TEST(MergeUsersTest, MultipleNamesAndEmails) { + std::vector users = { + User("user1", {"email1@example.com"}), + User("user2", {"email1@example.com", "email2@example.com"}), + User("user3", {"email3@example.com"})}; + + std::vector except_merge = { + User("user1", {"email1@example.com", "email2@example.com"}), + User("user3", {"email3@example.com"})}; + + std::vector merged_users = MergeUsers(users); + + EXPECT_EQ(merged_users.size(), except_merge.size()); + for (size_t i = 0; i < merged_users.size(); ++i) + EXPECT_EQ(merged_users[i], except_merge[i]); +} + +// Test case to check merging when there are no users +TEST(MergeUsersTest, NoUsers) { + std::vector users = {}; + + std::vector except_merge = {}; + + std::vector merged_users = MergeUsers(users); + + EXPECT_EQ(merged_users.size(), except_merge.size()); + for (size_t i = 0; i < merged_users.size(); ++i) + EXPECT_EQ(merged_users[i], except_merge[i]); +} + +// Test case to check merging of users with multiple overlapping emails and +// names +TEST(MergeUsersTest, ComplexOverlappingNamesAndEmails) { + std::vector users = { + User("user1", {"common@example.com", "unique1@example.com"}), + User("user2", {"common@example.com", "unique2@example.com"}), + User("user3", {"unique3@example.com"}), + User("user4", {"common@example.com", "unique4@example.com"}), + User("user5", {"unique1@example.com"})}; + + std::vector except_merge = { + User("user1", {"common@example.com", "unique1@example.com", + "unique2@example.com", "unique4@example.com"}), + User("user3", {"unique3@example.com"})}; + + std::vector merged_users = MergeUsers(users); + + EXPECT_EQ(merged_users.size(), except_merge.size()); + for (size_t i = 0; i < merged_users.size(); ++i) + EXPECT_EQ(merged_users[i], except_merge[i]); +} + +// Test case to check merging with users having nested relationships +TEST(MergeUsersTest, NestedRelationships) { + std::vector users = { + User("alice", {"alice@example.com", "bob@example.com"}), + User("bob", {"bob@example.com", "charlie@example.com"}), + User("charlie", {"charlie@example.com", "dave@example.com"}), + User("dave", {"dave@example.com"}), User("eve", {"eve@example.com"})}; + + std::vector except_merge = { + User("alice", {"alice@example.com", "bob@example.com", + "charlie@example.com", "dave@example.com"}), + User("eve", {"eve@example.com"})}; + + std::vector merged_users = MergeUsers(users); + + EXPECT_EQ(merged_users.size(), except_merge.size()); + for (size_t i = 0; i < merged_users.size(); ++i) + EXPECT_EQ(merged_users[i], except_merge[i]); +} + +// Test case to check merging when users have circular references +TEST(MergeUsersTest, CircularReferences) { + std::vector users = { + User("userA", {"emailA@example.com", "emailB@example.com"}), + User("userB", {"emailB@example.com", "emailC@example.com"}), + User("userC", {"emailC@example.com", "emailA@example.com"})}; + + std::vector except_merge = { + User("userA", + {"emailA@example.com", "emailB@example.com", "emailC@example.com"})}; + + std::vector merged_users = MergeUsers(users); + + EXPECT_EQ(merged_users.size(), except_merge.size()); + for (size_t i = 0; i < merged_users.size(); ++i) + EXPECT_EQ(merged_users[i], except_merge[i]); +} + +// Test case to check merging when users have different names but share all +// emails +TEST(MergeUsersTest, DifferentNamesSameEmails) { + std::vector users = {User("user1", {"shared@example.com"}), + User("user2", {"shared@example.com"}), + User("user3", {"shared@example.com"})}; + + std::vector except_merge = {User("user1", {"shared@example.com"})}; + + std::vector merged_users = MergeUsers(users); + + EXPECT_EQ(merged_users.size(), except_merge.size()); + for (size_t i = 0; i < merged_users.size(); ++i) + EXPECT_EQ(merged_users[i], except_merge[i]); +} diff --git a/additional_tasks/template_task/src/main.cpp b/additional_tasks/template_task/src/main.cpp deleted file mode 100644 index 76e8197..0000000 --- a/additional_tasks/template_task/src/main.cpp +++ /dev/null @@ -1 +0,0 @@ -int main() { return 0; } diff --git a/additional_tasks/template_task/src/test.cpp b/additional_tasks/template_task/src/test.cpp deleted file mode 100644 index 31df8b8..0000000 --- a/additional_tasks/template_task/src/test.cpp +++ /dev/null @@ -1,8 +0,0 @@ - -#include - -#include - -#include "utils.hpp" - -TEST(Template, Simple) { ASSERT_EQ(true, true); } diff --git a/additional_tasks/template_task/src/utils.cpp b/additional_tasks/template_task/src/utils.cpp deleted file mode 100644 index 0ee624c..0000000 --- a/additional_tasks/template_task/src/utils.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "utils.hpp" diff --git a/additional_tasks/template_task/src/utils.hpp b/additional_tasks/template_task/src/utils.hpp deleted file mode 100644 index 6f70f09..0000000 --- a/additional_tasks/template_task/src/utils.hpp +++ /dev/null @@ -1 +0,0 @@ -#pragma once From 5deaffe581df0bb6a71396229d79e70432c5282f Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 1 Dec 2024 17:02:12 +0000 Subject: [PATCH 40/42] revert changes --- additional_tasks/merge_users/README.md | 19 --- additional_tasks/merge_users/src/main.cpp | 17 --- .../merge_users/src/merge_users.cpp | 63 -------- .../merge_users/src/merge_users.hpp | 55 ------- additional_tasks/merge_users/src/test.cpp | 144 ------------------ .../CMakeLists.txt | 2 +- additional_tasks/template_task/README.md | 3 + additional_tasks/template_task/src/main.cpp | 1 + additional_tasks/template_task/src/test.cpp | 8 + additional_tasks/template_task/src/utils.cpp | 1 + additional_tasks/template_task/src/utils.hpp | 1 + 11 files changed, 15 insertions(+), 299 deletions(-) delete mode 100644 additional_tasks/merge_users/README.md delete mode 100644 additional_tasks/merge_users/src/main.cpp delete mode 100644 additional_tasks/merge_users/src/merge_users.cpp delete mode 100644 additional_tasks/merge_users/src/merge_users.hpp delete mode 100644 additional_tasks/merge_users/src/test.cpp rename additional_tasks/{merge_users => template_task}/CMakeLists.txt (96%) create mode 100644 additional_tasks/template_task/README.md create mode 100644 additional_tasks/template_task/src/main.cpp create mode 100644 additional_tasks/template_task/src/test.cpp create mode 100644 additional_tasks/template_task/src/utils.cpp create mode 100644 additional_tasks/template_task/src/utils.hpp diff --git a/additional_tasks/merge_users/README.md b/additional_tasks/merge_users/README.md deleted file mode 100644 index 0fc3b98..0000000 --- a/additional_tasks/merge_users/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Users merge - -There are n users, each of them corresponds to a list of emails (total m emails). For example: -user1 -> xxx@ya.ru, foo@gmail.com, lol@mail.ru -user2 -> foo@gmail.com, ups@pisem.net -user3 -> xyz@pisem.net, vasya@pupkin.com -user4 -> ups@pisem.net, aaa@bbb.ru -user5 -> xyz@pisem.net - -It is assumed that if two users have a common email, then they are the same user. - -We need to build and implement an algorithm that merges users. The output should be a list of users with their email addresses (the same as the input). - -In the above example, the answer to the task would be as follows: -user1 -> xxx@ya.ru, foo@gmail.com, lol@mail.ru, ups@pisem.net, aaa@bbb.ru -user3 -> xyz@pisem.net, vasya@pupkin.com - - -Translated with DeepL.com (free version) \ No newline at end of file diff --git a/additional_tasks/merge_users/src/main.cpp b/additional_tasks/merge_users/src/main.cpp deleted file mode 100644 index 8ff6e26..0000000 --- a/additional_tasks/merge_users/src/main.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "merge_users.hpp" - -int main() { - std::vector users = { - User("user1", {"xxx@ya.ru", "foo@gmail.com", "lol@mail.ru"}), - User("user2", {"foo@gmail.com", "ups@pisem.net"}), - User("user3", {"xyz@pisem.net", "vasya@pupkin.com"}), - User("user4", {"ups@pisem.net", "aaa@bbb.ru"}), - User("user5", {"xyz@pisem.net"})}; - - std::vector merged_users = MergeUsers(users); - - // Print the merged users and their emails - for (const auto& user : merged_users) std::cout << user << std::endl; - - return 0; -} \ No newline at end of file diff --git a/additional_tasks/merge_users/src/merge_users.cpp b/additional_tasks/merge_users/src/merge_users.cpp deleted file mode 100644 index 845a184..0000000 --- a/additional_tasks/merge_users/src/merge_users.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "merge_users.hpp" - -std::vector DFSMergeUtil(const Graph, UserData>& graph, - std::map& node_index) { - std::vector visited(graph.Size(), false); - std::vector merged_users; - - for (std::size_t i = 0; i < graph.Size(); ++i) - if (!visited[i]) { - std::set names; - std::set emails; - std::stack stack; - stack.push(i); - visited[i] = true; - - while (!stack.empty()) { - std::size_t u = stack.top(); - stack.pop(); - UserData node = graph[u]->data; - - if (node.type == Type::Name) - names.insert(node.data); - else - emails.insert(node.data); - - for (const auto& neighbor : graph[u]->adjacent) { - int v = node_index[neighbor->data.data]; - if (!visited[v]) { - visited[v] = true; - stack.push(v); - } - } - } - // Take the first user as representative - if (!names.empty()) merged_users.push_back(User(*names.cbegin(), emails)); - } - return merged_users; -} - -std::vector MergeUsers(std::vector& users) { - // Create a graph - Graph, UserData> graph; - - // Create a map to store the index of each node (string to integer) - std::map node_index; - - // Add vertices to the graph - for (const auto& user : users) { - if (node_index.find(user.name) == node_index.end()) { - node_index[user.name] = graph.Size(); - graph.AddVertex(UserData(user.name, Type::Name)); - } - for (const std::string& email : user.emails) { - if (node_index.find(email) == node_index.end()) { - node_index[email] = graph.Size(); - graph.AddVertex(UserData(email, Type::Email)); - } - graph.AddEdge(node_index[user.name], node_index[email]); - } - } - std::vector merged_users = DFSMergeUtil(graph, node_index); - return merged_users; -} diff --git a/additional_tasks/merge_users/src/merge_users.hpp b/additional_tasks/merge_users/src/merge_users.hpp deleted file mode 100644 index e6d635e..0000000 --- a/additional_tasks/merge_users/src/merge_users.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "graph.hpp" - -/// @brief Type of user data -enum Type { Name, Email }; - -/// @brief User data -struct UserData { - UserData(const std::string& data, Type type) : data(data), type(type) {} - std::string data; - Type type; -}; - -inline std::ostream& operator<<(std::ostream& os, const UserData& u_data) { - os << u_data.data; - return os; -} - -/// @brief User with a name and email -struct User { - User(const std::string& name, const std::set& emails) - : name(name), emails(emails) {} - std::string name; - std::set emails; // set to avoid duplicates -}; - -inline std::ostream& operator<<(std::ostream& os, const User& u) { - os << u.name << " -> "; - for (const std::string& email : u.emails) os << email << " "; - return os; -} - -inline bool operator==(const User& fu, const User& su) { - return fu.name == su.name && fu.emails == su.emails; -} - -/// @brief Perform Depth-First Search (DFS) to find connected components -/// @param graph : The graph to search -/// @param node_index : Quick access form data to index -/// @return Contatiner of merged users -std::vector DFSMergeUtil(const Graph, UserData>& graph, - std::map& node_index); - -/// @brief Merge users with matching emails -/// @param users : The list of users to merge -/// @return Merged users -std::vector MergeUsers(std::vector& users); \ No newline at end of file diff --git a/additional_tasks/merge_users/src/test.cpp b/additional_tasks/merge_users/src/test.cpp deleted file mode 100644 index 7d2db9d..0000000 --- a/additional_tasks/merge_users/src/test.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include - -#include "merge_users.hpp" - -// Test case to check merging of users with overlapping emails -TEST(MergeUsersTest, OverlappingEmails) { - std::vector users = { - User("user1", {"email1@example.com", "email2@example.com"}), - User("user2", {"email2@example.com", "email3@example.com"}), - User("user3", {"email4@example.com"})}; - - std::vector except_merge = { - User("user1", - {"email1@example.com", "email2@example.com", "email3@example.com"}), - User("user3", {"email4@example.com"})}; - - std::vector merged_users = MergeUsers(users); - - EXPECT_EQ(merged_users.size(), except_merge.size()); - for (size_t i = 0; i < merged_users.size(); ++i) - EXPECT_EQ(merged_users[i], except_merge[i]); -} - -// Test case to check merging of users with no overlapping emails -TEST(MergeUsersTest, NoOverlappingEmails) { - std::vector users = {User("user1", {"email1@example.com"}), - User("user2", {"email2@example.com"}), - User("user3", {"email3@example.com"})}; - - std::vector except_merge = users; - - std::vector merged_users = MergeUsers(users); - - EXPECT_EQ(merged_users.size(), except_merge.size()); - for (size_t i = 0; i < merged_users.size(); ++i) - EXPECT_EQ(merged_users[i], except_merge[i]); -} - -// Test case to check merging of users with multiple names and emails -TEST(MergeUsersTest, MultipleNamesAndEmails) { - std::vector users = { - User("user1", {"email1@example.com"}), - User("user2", {"email1@example.com", "email2@example.com"}), - User("user3", {"email3@example.com"})}; - - std::vector except_merge = { - User("user1", {"email1@example.com", "email2@example.com"}), - User("user3", {"email3@example.com"})}; - - std::vector merged_users = MergeUsers(users); - - EXPECT_EQ(merged_users.size(), except_merge.size()); - for (size_t i = 0; i < merged_users.size(); ++i) - EXPECT_EQ(merged_users[i], except_merge[i]); -} - -// Test case to check merging when there are no users -TEST(MergeUsersTest, NoUsers) { - std::vector users = {}; - - std::vector except_merge = {}; - - std::vector merged_users = MergeUsers(users); - - EXPECT_EQ(merged_users.size(), except_merge.size()); - for (size_t i = 0; i < merged_users.size(); ++i) - EXPECT_EQ(merged_users[i], except_merge[i]); -} - -// Test case to check merging of users with multiple overlapping emails and -// names -TEST(MergeUsersTest, ComplexOverlappingNamesAndEmails) { - std::vector users = { - User("user1", {"common@example.com", "unique1@example.com"}), - User("user2", {"common@example.com", "unique2@example.com"}), - User("user3", {"unique3@example.com"}), - User("user4", {"common@example.com", "unique4@example.com"}), - User("user5", {"unique1@example.com"})}; - - std::vector except_merge = { - User("user1", {"common@example.com", "unique1@example.com", - "unique2@example.com", "unique4@example.com"}), - User("user3", {"unique3@example.com"})}; - - std::vector merged_users = MergeUsers(users); - - EXPECT_EQ(merged_users.size(), except_merge.size()); - for (size_t i = 0; i < merged_users.size(); ++i) - EXPECT_EQ(merged_users[i], except_merge[i]); -} - -// Test case to check merging with users having nested relationships -TEST(MergeUsersTest, NestedRelationships) { - std::vector users = { - User("alice", {"alice@example.com", "bob@example.com"}), - User("bob", {"bob@example.com", "charlie@example.com"}), - User("charlie", {"charlie@example.com", "dave@example.com"}), - User("dave", {"dave@example.com"}), User("eve", {"eve@example.com"})}; - - std::vector except_merge = { - User("alice", {"alice@example.com", "bob@example.com", - "charlie@example.com", "dave@example.com"}), - User("eve", {"eve@example.com"})}; - - std::vector merged_users = MergeUsers(users); - - EXPECT_EQ(merged_users.size(), except_merge.size()); - for (size_t i = 0; i < merged_users.size(); ++i) - EXPECT_EQ(merged_users[i], except_merge[i]); -} - -// Test case to check merging when users have circular references -TEST(MergeUsersTest, CircularReferences) { - std::vector users = { - User("userA", {"emailA@example.com", "emailB@example.com"}), - User("userB", {"emailB@example.com", "emailC@example.com"}), - User("userC", {"emailC@example.com", "emailA@example.com"})}; - - std::vector except_merge = { - User("userA", - {"emailA@example.com", "emailB@example.com", "emailC@example.com"})}; - - std::vector merged_users = MergeUsers(users); - - EXPECT_EQ(merged_users.size(), except_merge.size()); - for (size_t i = 0; i < merged_users.size(); ++i) - EXPECT_EQ(merged_users[i], except_merge[i]); -} - -// Test case to check merging when users have different names but share all -// emails -TEST(MergeUsersTest, DifferentNamesSameEmails) { - std::vector users = {User("user1", {"shared@example.com"}), - User("user2", {"shared@example.com"}), - User("user3", {"shared@example.com"})}; - - std::vector except_merge = {User("user1", {"shared@example.com"})}; - - std::vector merged_users = MergeUsers(users); - - EXPECT_EQ(merged_users.size(), except_merge.size()); - for (size_t i = 0; i < merged_users.size(); ++i) - EXPECT_EQ(merged_users[i], except_merge[i]); -} diff --git a/additional_tasks/merge_users/CMakeLists.txt b/additional_tasks/template_task/CMakeLists.txt similarity index 96% rename from additional_tasks/merge_users/CMakeLists.txt rename to additional_tasks/template_task/CMakeLists.txt index cb87577..eed780f 100644 --- a/additional_tasks/merge_users/CMakeLists.txt +++ b/additional_tasks/template_task/CMakeLists.txt @@ -37,4 +37,4 @@ target_link_libraries( ) include(GoogleTest) -gtest_discover_tests(${PROJECT_NAME}_tests) +gtest_discover_tests(${PROJECT_NAME}_tests) \ No newline at end of file diff --git a/additional_tasks/template_task/README.md b/additional_tasks/template_task/README.md new file mode 100644 index 0000000..8e59f99 --- /dev/null +++ b/additional_tasks/template_task/README.md @@ -0,0 +1,3 @@ +# Шаблонная задача + +Описание задачи \ No newline at end of file diff --git a/additional_tasks/template_task/src/main.cpp b/additional_tasks/template_task/src/main.cpp new file mode 100644 index 0000000..c3aeba4 --- /dev/null +++ b/additional_tasks/template_task/src/main.cpp @@ -0,0 +1 @@ +int main() { return 0; } \ No newline at end of file diff --git a/additional_tasks/template_task/src/test.cpp b/additional_tasks/template_task/src/test.cpp new file mode 100644 index 0000000..31df8b8 --- /dev/null +++ b/additional_tasks/template_task/src/test.cpp @@ -0,0 +1,8 @@ + +#include + +#include + +#include "utils.hpp" + +TEST(Template, Simple) { ASSERT_EQ(true, true); } diff --git a/additional_tasks/template_task/src/utils.cpp b/additional_tasks/template_task/src/utils.cpp new file mode 100644 index 0000000..0ee624c --- /dev/null +++ b/additional_tasks/template_task/src/utils.cpp @@ -0,0 +1 @@ +#include "utils.hpp" diff --git a/additional_tasks/template_task/src/utils.hpp b/additional_tasks/template_task/src/utils.hpp new file mode 100644 index 0000000..7b9637e --- /dev/null +++ b/additional_tasks/template_task/src/utils.hpp @@ -0,0 +1 @@ +#pragma once \ No newline at end of file From 8bd78f8ca548be65b21c2f8a71fd0948929cfbc3 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 1 Dec 2024 17:07:51 +0000 Subject: [PATCH 41/42] revert changes --- additional_tasks/template_task/CMakeLists.txt | 2 +- additional_tasks/template_task/src/main.cpp | 2 +- additional_tasks/template_task/src/utils.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/additional_tasks/template_task/CMakeLists.txt b/additional_tasks/template_task/CMakeLists.txt index eed780f..cb87577 100644 --- a/additional_tasks/template_task/CMakeLists.txt +++ b/additional_tasks/template_task/CMakeLists.txt @@ -37,4 +37,4 @@ target_link_libraries( ) include(GoogleTest) -gtest_discover_tests(${PROJECT_NAME}_tests) \ No newline at end of file +gtest_discover_tests(${PROJECT_NAME}_tests) diff --git a/additional_tasks/template_task/src/main.cpp b/additional_tasks/template_task/src/main.cpp index c3aeba4..76e8197 100644 --- a/additional_tasks/template_task/src/main.cpp +++ b/additional_tasks/template_task/src/main.cpp @@ -1 +1 @@ -int main() { return 0; } \ No newline at end of file +int main() { return 0; } diff --git a/additional_tasks/template_task/src/utils.hpp b/additional_tasks/template_task/src/utils.hpp index 7b9637e..6f70f09 100644 --- a/additional_tasks/template_task/src/utils.hpp +++ b/additional_tasks/template_task/src/utils.hpp @@ -1 +1 @@ -#pragma once \ No newline at end of file +#pragma once From cdb6dd561df2b858446d3c79856cc461c4031cfc Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Wed, 15 Jan 2025 17:59:33 +0000 Subject: [PATCH 42/42] bring missing clang-tidy configs back --- .github/workflows/clang-tidy-review.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/clang-tidy-review.yaml b/.github/workflows/clang-tidy-review.yaml index cc36367..522dc44 100644 --- a/.github/workflows/clang-tidy-review.yaml +++ b/.github/workflows/clang-tidy-review.yaml @@ -14,6 +14,8 @@ jobs: - uses: ZedThree/clang-tidy-review@v0.19.0 with: + apt_packages: libgtest-dev + clang_tidy_version: 18 clang_tidy_checks: '-*,performance-*,bugprone-*,clang-analyzer-*,cppcoreguidelines-*,mpi-*,misc-*,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-avoid-magic-numbers,-clang-diagnostic-error,-misc-no-recursion,-cppcoreguidelines-owning-memory,-bugprone-narrowing-conversions,-bugprone-easily-swappable-parameters,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-special-member-functions,-cppcoreguidelines-init-variables,-misc-include-cleaner' split_workflow: true