From f0bd3c8862c2c57176a3c5253a16f8d40fad6468 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sat, 21 Sep 2024 19:56:58 +0000 Subject: [PATCH 01/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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 fa8ba684e2ce01e11a9090586d4df569a5045130 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 21:11:07 +0000 Subject: [PATCH 08/19] 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 f13ca9fbc52016d4ccb197bb8b4ade562353b05d Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 21:11:32 +0000 Subject: [PATCH 09/19] 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 29645117aeb19040448d64b03612908be2c5762d Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 22 Sep 2024 22:32:12 +0000 Subject: [PATCH 10/19] 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 5ae79676ae1b715b5f443f2116eb0e6fdc14ad9d Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 23 Sep 2024 14:28:23 +0000 Subject: [PATCH 11/19] 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 bbf95ffafc5c24191ba10e3493ddc105d751c63a Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Thu, 31 Oct 2024 12:49:35 +0000 Subject: [PATCH 12/19] 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 9c125dde51f80dba8000d612076a80c99c489286 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 1 Nov 2024 11:15:45 +0000 Subject: [PATCH 13/19] 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 c8bafd091a22db99d5237a598b6f63e07fb5cb94 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Fri, 15 Nov 2024 12:06:08 +0000 Subject: [PATCH 14/19] 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 ec36842ee285e53bd39833f63f5010e84f30e2a6 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 18 Nov 2024 11:08:57 +0000 Subject: [PATCH 15/19] 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 487768a..4c95e90 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(); } @@ -107,10 +108,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 6a07b97a44805354dad1b276037cbcd2175fac2d Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 18 Nov 2024 13:25:46 +0000 Subject: [PATCH 16/19] format changes --- lib/src/graph.hpp | 13 +++++++------ lib/src/weighted_graph.hpp | 16 +++++++++------- 2 files changed, 16 insertions(+), 13 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 4c95e90..35df43a 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()); } /** @@ -110,7 +111,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] << ") "; } From 40382cc42fe84ce4b189ef060e5577811c58ae87 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Mon, 18 Nov 2024 23:45:28 +0000 Subject: [PATCH 17/19] weaken graph concept --- lib/src/graph.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/graph.hpp b/lib/src/graph.hpp index 97cf7db..7a4920b 100644 --- a/lib/src/graph.hpp +++ b/lib/src/graph.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -18,7 +17,7 @@ struct Vertex { }; template -concept IsVertex = std::derived_from>; +concept IsVertex = std::is_base_of, T>::value; /// @brief Basic graph /// @tparam VertexType From f4641dd8124ae2f33cdc219a457eadb5741cc95a Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 1 Dec 2024 15:34:43 +0000 Subject: [PATCH 18/19] 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 594122f5250f897d5261824a476b7aa5e0527cf6 Mon Sep 17 00:00:00 2001 From: Ilya_Rybalkin Date: Sun, 1 Dec 2024 15:35:01 +0000 Subject: [PATCH 19/19] 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