From ac67f77201b26c23191bc3fd9bab59cc8bca07c5 Mon Sep 17 00:00:00 2001 From: Vlad Date: Wed, 18 Dec 2024 17:53:10 +0300 Subject: [PATCH 1/2] added a graph class --- CMakeLists.txt | 22 +++-- include/CMakeLists.txt | 0 include/graph/graph.h | 47 +++++++++++ src/CMakeLists.txt | 0 src/graph/CMakeLists.txt | 7 ++ src/graph/graph.cpp | 146 +++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 14 ++-- test/main.cpp | 2 +- test/test_graph.cpp | 173 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 396 insertions(+), 15 deletions(-) delete mode 100644 include/CMakeLists.txt create mode 100644 include/graph/graph.h delete mode 100644 src/CMakeLists.txt create mode 100644 src/graph/CMakeLists.txt create mode 100644 src/graph/graph.cpp create mode 100644 test/test_graph.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a8e8360..be0cd36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,19 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.15) -project(cpp_template) +set(ProjectName "itlab") -include(cmake/configure.cmake) +project(${ProjectName}) include_directories(include) -enable_testing() - -add_subdirectory(3rdparty) -add_subdirectory(app) -add_subdirectory(include) -add_subdirectory(src) +add_subdirectory(3rdparty/googletest) +add_subdirectory(src/graph) add_subdirectory(test) + +# REPORT +message( STATUS "") +message( STATUS "General configuration for ${PROJECT_NAME}") +message( STATUS "======================================") +message( STATUS "") +message( STATUS " Configuration: ${CMAKE_BUILD_TYPE}") +message( STATUS "") \ No newline at end of file diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt deleted file mode 100644 index e69de29..0000000 diff --git a/include/graph/graph.h b/include/graph/graph.h new file mode 100644 index 0000000..0c68d68 --- /dev/null +++ b/include/graph/graph.h @@ -0,0 +1,47 @@ +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include +#include +#include + +class Vertex { +private: + int id; + std::list neighbors; + +public: + Vertex(int id); + void addNeighbor(int neighbor); + void removeNeighbor(int neighbor); + void print() const; + int getId() const; + const std::list& getNeighbors() const; +}; + + + +class Graph { +private: + std::unordered_map vertices; + +public: + + Graph(); + + void addVertex(int id); + void getVertex() const; + void addEdge(int u, int v); + void removeEdge(int u, int v); + void removeVertex(int id); + int vertexCount() const; + int edgeCount() const; + bool empty() const; + void printGraph() const; + bool hasPath(int u, int v); + std::vector BFS(int start); + ~Graph(); +}; + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/graph/CMakeLists.txt b/src/graph/CMakeLists.txt new file mode 100644 index 0000000..af77d7d --- /dev/null +++ b/src/graph/CMakeLists.txt @@ -0,0 +1,7 @@ +file(GLOB_RECURSE HEADER_FILES "${CMAKE_SOURCE_DIR}/include/*.h") +file(GLOB_RECURSE SOURCE_FILES "${CMAKE_SOURCE_DIR}/src/*.cpp") + +add_library(${ProjectName} STATIC ${SOURCE_FILES} ${HEADER_FILES}) +target_sources(${ProjectName} PRIVATE ${HEADER_FILES}) + +target_include_directories(${ProjectName} PUBLIC ${CMAKE_SOURCE_DIR}/src) \ No newline at end of file diff --git a/src/graph/graph.cpp b/src/graph/graph.cpp new file mode 100644 index 0000000..c3cc8b0 --- /dev/null +++ b/src/graph/graph.cpp @@ -0,0 +1,146 @@ +#include "./graph/graph.h" + +Vertex::Vertex(int id) : id(id) {} + +void Vertex::addNeighbor(int neighbor) { + if (neighbor != id) { + neighbors.push_back(neighbor); + } +} + +void Vertex::removeNeighbor(int neighbor) { + neighbors.remove(neighbor); +} + +void Vertex::print() const { + std::cout << id << ": "; + for (const int& neighbor : neighbors) { + std::cout << neighbor << " "; + } + std::cout << std::endl; +} + +int Vertex::getId() const { + return id; +} + +const std::list& Vertex::getNeighbors() const { + return neighbors; +} + +Graph::Graph() {} + +void Graph::addVertex(int id) { + if (vertices.find(id) == vertices.end()) { + vertices[id] = new Vertex(id); + } +} + +void Graph::getVertex() const { + if (!this->empty()) { + for (auto it = vertices.begin(); it != vertices.end(); it++) + std::cout << it->first << " "; + std::cout << std::endl; + } +} + +void Graph::addEdge(int u, int v) { + if (vertices.find(u) == vertices.end()) { addVertex(u); } + if (vertices.find(v) == vertices.end()) { addVertex(v); } + vertices[u]->addNeighbor(v); +} + +void Graph::removeEdge(int u, int v) { + if (vertices.find(u) != vertices.end()) { + vertices[u]->removeNeighbor(v); + } +} + +void Graph::removeVertex(int id) { + for (auto& pair : vertices) { pair.second->removeNeighbor(id); } + auto it = vertices.find(id); + if (it != vertices.end()) { + delete it->second; + vertices.erase(it); + } +} + +int Graph::vertexCount() const { + int count = 0; + for (auto it = vertices.begin(); it != vertices.end(); it++) + count++; + return count; +} + +int Graph::edgeCount() const { + int count = 0; + for (auto it = vertices.begin(); it != vertices.end(); it++) { + count += (it->second->getNeighbors()).size(); + } + return count; +} + + +bool Graph::empty() const { + return vertices.empty(); +} + +void Graph::printGraph() const { + for (const auto& pair : vertices) { + pair.second->print(); + } +} + +bool Graph::hasPath(int u, int v) { + if (vertices.find(u) != vertices.end() && vertices.find(v) != vertices.end()) { + std::unordered_map visited; + std::queue queue; + queue.push(u); + + while (!queue.empty()) { + int current = queue.front(); + queue.pop(); + if (current == v) { return true; } + visited[current] = true; + + for (const int& neighbor : vertices[current]->getNeighbors()) + if (!visited[neighbor]) + queue.push(neighbor); + + } + return false; + } +} + +std::vector Graph::BFS(int start) { + std::vector traversal_order; + std::unordered_map visited; + std::queue queue; + + visited[start] = true; + queue.push(start); + + while (!queue.empty()) { + int current = queue.front(); + queue.pop(); + traversal_order.push_back(current); + + if (vertices.find(current) != vertices.end()) { + for (const int& neighbor : vertices[current]->getNeighbors()) { + if (!visited[neighbor]) { + visited[neighbor] = true; + queue.push(neighbor); + } + } + } + } + //for (int i : traversal_order) + // std::cout << i << " "; + return traversal_order; +} + +Graph::~Graph() { + for (auto& pair : vertices) { + delete pair.second; + } +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9dada0c..14bf041 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,10 @@ -file(GLOB_RECURSE TEST_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +file(GLOB_RECURSE TEST_FILES ./*.cpp) -add_executable(run_tests ${TEST_SRC_FILES}) -target_link_libraries(run_tests PUBLIC - gtest_main -) +set(TestsName "Tests") + +add_executable(${TestsName} ${TEST_FILES}) + +target_link_libraries(${TestsName} PRIVATE ${ProjectName} gtest) + +enable_testing() +add_test(NAME ${TestsName} COMMAND ${TestsName}) \ No newline at end of file diff --git a/test/main.cpp b/test/main.cpp index 4d820af..a0bda37 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,4 +1,4 @@ -#include +#include int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/test/test_graph.cpp b/test/test_graph.cpp new file mode 100644 index 0000000..d0fe2c0 --- /dev/null +++ b/test/test_graph.cpp @@ -0,0 +1,173 @@ +#include "./graph/graph.h" +#include "./graph/graph.cpp" +#include + + +TEST(Graph, can_create_graph) +{ + ASSERT_NO_THROW(Graph g); +} + +TEST(Graph, can_add_vertex_to_graph) +{ + Graph g; + + ASSERT_NO_THROW(g.addVertex(1)); +} + +TEST(Graph, can_add_edge_to_graph) +{ + Graph g; + + ASSERT_NO_THROW(g.addEdge(1,0)); +} + +TEST(Graph, can_add_edge_with_same_id_to_graph) +{ + Graph g; + + ASSERT_NO_THROW(g.addEdge(1, 1)); +} + +TEST(Graph, can_add_vertex_and_edge_to_graph) +{ + Graph g; + + ASSERT_NO_THROW(g.addEdge(1, 0)); + ASSERT_NO_THROW(g.addVertex(1)); +} + +TEST(Graph, can_get_vertex) +{ + Graph g; + g.addEdge(1, 0); + + ASSERT_NO_THROW(g.getVertex()); +} + +TEST(Graph, can_remove_vertex) +{ + Graph g; + g.addEdge(1, 0); + + g.removeVertex(1); + + ASSERT_EQ(g.vertexCount(),1); +} + +TEST(Graph, can_get_vertex_count) +{ + Graph g; + + g.addEdge(1, 0); + g.addVertex(2); + g.addVertex(3); + g.removeVertex(1); + g.addVertex(1); + g.removeVertex(3); + + ASSERT_EQ(g.vertexCount(), 3); +} + +TEST(Graph, can_get_edge_count) +{ + Graph g; + + g.addEdge(1, 0); + g.addEdge(2, 0); + g.addEdge(0, 2); + g.addEdge(2, 2); + + ASSERT_EQ(g.edgeCount(), 3); +} + +TEST(Graph, check_graph_is_empty) +{ + Graph g; + + ASSERT_TRUE(g.empty()); +} + +TEST(Graph, check_graph_is_not_empty) +{ + Graph g; + + g.addEdge(1, 0); + + ASSERT_FALSE(g.empty()); +} + +TEST(Graph, check_graph_no_path_between_vertexes) +{ + Graph g; + + g.addEdge(0,1); + g.addEdge(0, 3); + g.addEdge(1, 2); + g.addEdge(3, 1); + + ASSERT_FALSE(g.hasPath(1,0)); +} + +TEST(Graph, check_graph_has_path_between_vertexes) +{ + Graph g; + + g.addEdge(0, 1); + g.addEdge(0, 3); + g.addEdge(1, 2); + g.addEdge(3, 1); + + ASSERT_TRUE(g.hasPath(3,1)); +} + +TEST(Graph, check_graph_can_find_path_between_vertexes_after_delete) +{ + Graph g; + + g.addEdge(0, 1); + g.addEdge(0, 3); + g.addEdge(1, 2); + g.addEdge(3, 1); + g.removeVertex(3); + + ASSERT_FALSE(g.hasPath(3, 1)); + ASSERT_FALSE(g.hasPath(0, 3)); +} + +TEST(Graph, can_create_bfs_path) +{ + Graph g; + + g.addEdge(0, 1); + g.addEdge(0, 3); + g.addEdge(1, 2); + + ASSERT_NO_THROW(g.BFS(0)); +} + +TEST(Graph, can_create_bfs_path_in_empty_graph) +{ + Graph g; + + ASSERT_NO_THROW(g.BFS(0)); +} + +TEST(Graph, check_bfs_path) +{ + Graph g; + std::vector v1 = { 0,1,3,2,4,6,7,5,8,9 }; + + g.addEdge(0, 1); + g.addEdge(0, 3); + g.addEdge(1, 2); + g.addEdge(3, 4); + g.addEdge(4, 5); + g.addEdge(3,6); + g.addEdge(3, 7); + g.addEdge(7,8); + g.addEdge(8, 9); + std::vector v = g.BFS(0); + + ASSERT_EQ(v, v1); +} \ No newline at end of file From 5f36230bfedf2d85a8178acdbea96ff1e4448591 Mon Sep 17 00:00:00 2001 From: Vlad Date: Fri, 20 Dec 2024 02:29:18 +0300 Subject: [PATCH 2/2] gtest dir fix --- CMakeLists.txt | 2 +- test/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be0cd36..75658c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ project(${ProjectName}) include_directories(include) -add_subdirectory(3rdparty/googletest) +add_subdirectory(3rdparty/googletest/gtest) add_subdirectory(src/graph) add_subdirectory(test) diff --git a/test/main.cpp b/test/main.cpp index a0bda37..47f4482 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -3,4 +3,4 @@ int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} +} \ No newline at end of file