From cb566580bd3b674d6aa429cc13648f0faf9f7204 Mon Sep 17 00:00:00 2001 From: Samuel Oberhofer Date: Tue, 7 Jun 2022 23:13:44 +0200 Subject: [PATCH] 3.3a solved --- Uebung 3/Uebung3_2/extendedgraph2.h | 1 - Uebung 3/Uebung3_3/Makefile | 51 ++++++ Uebung 3/Uebung3_3/edge.h | 20 +++ Uebung 3/Uebung3_3/extendedgraph2.cpp | 249 ++++++++++++++++++++++++++ Uebung 3/Uebung3_3/extendedgraph2.h | 72 ++++++++ Uebung 3/Uebung3_3/main.cpp | 75 ++++++++ 6 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 Uebung 3/Uebung3_3/Makefile create mode 100644 Uebung 3/Uebung3_3/edge.h create mode 100644 Uebung 3/Uebung3_3/extendedgraph2.cpp create mode 100644 Uebung 3/Uebung3_3/extendedgraph2.h create mode 100644 Uebung 3/Uebung3_3/main.cpp diff --git a/Uebung 3/Uebung3_2/extendedgraph2.h b/Uebung 3/Uebung3_2/extendedgraph2.h index 70ed69b..2be149b 100644 --- a/Uebung 3/Uebung3_2/extendedgraph2.h +++ b/Uebung 3/Uebung3_2/extendedgraph2.h @@ -68,5 +68,4 @@ public: void depthFirstSearch(std::string vertex); void doTheDFS(std::string vertex, std::vector &visited); - int getEdgeWeight(std::string sourceVertex, std::string targetVertex); }; \ No newline at end of file diff --git a/Uebung 3/Uebung3_3/Makefile b/Uebung 3/Uebung3_3/Makefile new file mode 100644 index 0000000..9981ead --- /dev/null +++ b/Uebung 3/Uebung3_3/Makefile @@ -0,0 +1,51 @@ + +# Name of the binary for Development +BINARY = main +# Name of the binary for Release +FINAL = prototyp +# Object files +OBJS = extendedgraph2.o main.o +# Compiler flags +CFLAGS = -Werror -Wall -std=c++17 -fsanitize=address,undefined -g +# Linker flags +LFLAGS = -fsanitize=address,undefined +#Which Compiler to use +COMPILER = c++ + + +# all target: builds all important targets +all: binary + +final : ${OBJS} + ${COMPILER} ${LFLAGS} -o ${FINAL} ${OBJS} + +binary : ${OBJS} + ${COMPILER} ${LFLAGS} -o ${BINARY} ${OBJS} + +# Links the binary +${BINARY} : ${OBJS} + ${COMPILER} ${LFLAGS} -o ${BINARY} ${OBJS} + + +# Compiles a source-file (any file with file extension .c) into an object-file +# +# "%" is a wildcard which matches every file-name (similar to * in regular expressions) +# Such a rule is called a pattern rule (because it matches a pattern, see https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html), +# which are a form of so called implicit rules (see https://www.gnu.org/software/make/manual/html_node/Implicit-Rules.html) +# "$@" and "$<" are so called automatic variables (see https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html) +%.o : %.cpp + ${COMPILER} -c ${CFLAGS} -o $@ $< + + +# Rules can not only be used for compiling a program but also for executing a program +run: ${BINARY} + ./${BINARY} + + +# Delete all build artifacts +clean : + rm -rf ${BINARY} ${OBJS} + + +# all and clean are a "phony" targets, meaning they are no files +.PHONY : all clean diff --git a/Uebung 3/Uebung3_3/edge.h b/Uebung 3/Uebung3_3/edge.h new file mode 100644 index 0000000..7a6e454 --- /dev/null +++ b/Uebung 3/Uebung3_3/edge.h @@ -0,0 +1,20 @@ +#include + +#pragma once + +/* -- Struct Edge -- */ +class Edge { +private: + std::string m_src; // string source; beginning of the directed connection + std::string m_dest; // string destination; end of the directed connection + int m_weight; // weight +public: + Edge(std::string src, std::string dest, int weight) + : m_src(src), m_dest(dest), m_weight(weight){}; + const int &getWeight() const { return this->m_weight; }; + void setWeight(int weight) { this->m_weight = weight; }; + const std::string &getSrc() const { return this->m_src; }; + void setSrc(std::string src) { this->m_src = src; }; + const std::string &getDest() const { return this->m_dest; }; + void setDest(std::string dest) { this->m_dest = dest; }; +}; diff --git a/Uebung 3/Uebung3_3/extendedgraph2.cpp b/Uebung 3/Uebung3_3/extendedgraph2.cpp new file mode 100644 index 0000000..3bb7d2c --- /dev/null +++ b/Uebung 3/Uebung3_3/extendedgraph2.cpp @@ -0,0 +1,249 @@ +#include "extendedgraph2.h" +#include + +ExtendedGraph::ExtendedGraph() { // Default Constructor + this->vertices = + std::vector(0); // Empty Vector for this->vertices + this->adjacencyMatrix.resize( + 0, std::vector(0)); // 0x0 Matrix for this->adjacencyMatrix +} + +/* -- + Constructor with params +-- */ +ExtendedGraph::ExtendedGraph(const std::vector &vertices, + const std::vector &edges) { + this->vertices = vertices; // definition of this->vertex through parameter + // vertices (type: std::vector) + this->adjacencyMatrix.resize( + vertices.size(), + std::vector( + this->vertices.size())); // creation of an NxN Matrix, based on the + // size of vertices + + for (int i = 0; i < edges.size(); i++) { + insertEdge(edges[i]); // edges are added one by one, utilizing the + // insertEdge()-Function + } +} + +/* -- / +Function to insert a vertex into the Graph; + - takes one argument of type std::string that represents a vertex + - returns void +/ -- */ +void ExtendedGraph::insertVertex(const std::string &vertex) { + if (this->resolveVertex(vertex) != -1) { /* -- */ + std::cerr + << "Vertex already in Graph!\n"; /* Calls this->resolveVertex to check + if a given vertex is already in the + Graph. Returns with an error, if + this is the case. */ + return; /* -- */ + } + this->vertices.push_back(vertex); // adds a vertetx via the push_back + // function provided by std::vector + this->adjacencyMatrix.resize( + this->vertices.size(), + std::vector(this->vertices.size())); // resizes the adjacencyMatrix + // to the new size + for (int i = 0; i < this->vertices.size(); i++) { /* -- */ + adjacencyMatrix[i].resize( + this->vertices.size()); /* resizes every "sub" vector of the matrix to + the new size */ + } /* -- */ +} + +/* -- / +Function to delete a vertex from the Graph; + - takes one argument of type std::string that represents a vertex + - returns void +/ -- */ +void ExtendedGraph::deleteVertex(const std::string &vertex) { + int index = this->resolveVertex(vertex); + if (index == -1) { /* -- */ + std::cerr << "Vertex not found\n"; /* Calls this->resolveVertex to check if + a given vertex is already in the + Graph. Returns with an error, if this + is the case. */ + return; /* -- */ + } + this->vertices.erase( + this->vertices.begin() + + index); // erases the vertex at position "index" from this->vertices + + this->adjacencyMatrix.erase( + this->adjacencyMatrix.begin() + + index); // erases the entries from the adjacencyMatrix at "column" + // position "index" + for (int i = 0; i < this->adjacencyMatrix[0].size(); i++) { /* -- */ + this->adjacencyMatrix[i].erase(this->adjacencyMatrix[i].begin() + + index); /* erases the entries from the + adjacencyMatrix in every "row" */ + } /* -- */ +} + +/* -- / +Function to insert an Edge + - takes one argument of type Edge that represents an edge + - returns void +/ -- */ +void ExtendedGraph::insertEdge(const Edge &edge) { + int col = this->resolveVertex( + edge.getSrc()); // resolves the src of the edge to the index within the + // adjacencyMatrix + int row = this->resolveVertex( + edge.getDest()); // resolves the dest of the edge to the index within the + // adjacencyMatrix + if (col == -1 || row == -1) { /* -- */ + std::cerr << "Vertex not found!\n"; /* Calls this->resolveVertex to check + if a given vertex is already in the + Graph. Returns with an error, if this + is the case. */ + return; /* -- */ + } + + this->adjacencyMatrix[col][row] = + edge.getWeight(); // sets the value of the adjacencyMatrix at position + // [col][row] to the weight of the edge +} + +/* -- / +Function to delete an Edge + - takes one argument of type Edge that represents an edge + - returns void +/ -- */ +void ExtendedGraph::deleteEdge(const Edge &edge) { + int col = this->resolveVertex( + edge.getSrc()); // resolves the src of the edge to the index within the + // adjacencyMatrix + int row = this->resolveVertex( + edge.getDest()); // resolves the dest of the edge to the index within the + // adjacencyMatrix + if (col == -1 || row == -1) { /* -- */ + std::cerr << "Vertex not found!\n"; /* Calls this->resolveVertex to check + if a given vertex is already in the + Graph. Returns with an error, if this + is the case. */ + return; /* -- */ + } + this->adjacencyMatrix[col][row] = + 0; // sets the value of the adjacencyMatrix at position [col][row] to 0 +} + +/* -- / +Function to check whether vertex v2 is adjacent to vertex v1 + - takes one argument of type Edge that represents an edge + - returns void +/ -- */ +bool ExtendedGraph::adjacent(const std::string &vertex1, + const std::string &vertex2) { + int indexVertex1 = this->resolveVertex(vertex1); + int indexVertex2 = this->resolveVertex(vertex2); + if (indexVertex1 == -1 || indexVertex2 == -1) { + std::cerr << "Vertex not found!\n"; + return false; + } + // As adjacency is an equivalency relation, we need to check for a possible + // relation in both direction. This can be achieved by swapping the the + // position specifications of the adjacencyMatrix (from + // [indexVertex1][indexVertex2] to [indexVertex2][indexVertex1]). + if (this->adjacencyMatrix[indexVertex1][indexVertex2] != 0 || + this->adjacencyMatrix[indexVertex2][indexVertex1] != 0) { + return true; // if a connection (in any direction) is found, return true + } else { + return false; // else, return false + } +} + +/* -- / +Function that returns an std::vector of std::string representing the +neighbouring vertices of the parameter std::string vertex. Other than adjacent, +neighbourhood is a directed relationship, which means that a vertex "A" can be +the neighbour of "B", but this does not automatically imply that "B" is the +neighbour of "A". + - takes one argument of type std::string that represents a vertex + - returns a std::vector of std::string +/ -- */ +std::vector ExtendedGraph::neighbours(const std::string &vertex) { + int indexVertex = this->resolveVertex( + vertex); // resolves the vertex to the index within the adjacencyMatrix + std::vector resVector = + {}; // initializes an empty std::vetor of std::string + for (int i = 0; i < this->adjacencyMatrix[indexVertex].size(); + i++) { /* Loops through all entries of the subvector of + adjacencyMatrix[indexVertex] */ + if (this->adjacencyMatrix[indexVertex][i] != + 0) { /* and checks if the entry at position [indexVertex][i] is not 0. + */ + resVector.push_back( + this->vertices[i]); /* If the condition is fulfilled, add the vertex + (name) to the result vector resVector */ + } + } + return resVector; +} + +/* -- / +Function that prints the current Graph's adjacencyMatrix. + - prints the Graph by utilizing std::cout + - returns void +/ -- */ +void ExtendedGraph::printGraph() { + std::cout << "--------------------------------------------\n"; + std::cout << "\t\t\t"; + for (int i = 0; i < this->vertices.size(); i++) { + std::cout << this->vertices[i] << "\t"; + } + std::cout << "\n"; + for (int i = 0; i < this->vertices.size(); i++) { + std::cout << " " << this->vertices[i] << "\t\t-->\t"; + for (int j = 0; j < this->vertices.size(); j++) { + std::cout << this->adjacencyMatrix[i][j] << "\t"; + } + std::cout << "\n"; + } + std::cout << "--------------------------------------------\n"; +}; + +/* -- / +Function that resolves a parameter std::string name and returns it's index +within the this->vertices vector; between vertices of type std::string and the +corresponding index (in the adjacencyMatrix) of type int. + - takes one argument of type std::string that represents a vertex + - returns an int representing the vertex's index in the adjacencyMatrix; + - function returns -1 in case the resolution of the name is unsuccessful +/ -- */ +int ExtendedGraph::resolveVertex(const std::string &vertexName) { + for (int i = 0; i < this->vertices.size(); i++) { + if (this->vertices[i] == vertexName) { + return i; + } + } + return -1; +} + +int ExtendedGraph::getEdgeWeight(std::string sourceVertex, + std::string targetVertex) { + for (uint8_t i = 0; i < this->vertices.size(); i++) { + for (uint8_t j = 0; j < this->vertices[i].size(); j++) { + if (this->vertices[i] == sourceVertex && + this->vertices[j] == targetVertex) { + return this->adjacencyMatrix[i][j]; + } + } + } + return -1; +} + +void ExtendedGraph::setEdgeWeight(std::string sourceVertex, + std::string targetVertex, int weight) { + for (uint8_t i = 0; i < this->vertices.size(); i++) { + for (uint8_t j = 0; j < this->vertices[i].size(); j++) { + if (this->vertices[i] == sourceVertex && + this->vertices[j] == targetVertex) { + this->adjacencyMatrix[i][j] = weight; + } + } + }; +}; \ No newline at end of file diff --git a/Uebung 3/Uebung3_3/extendedgraph2.h b/Uebung 3/Uebung3_3/extendedgraph2.h new file mode 100644 index 0000000..71cef28 --- /dev/null +++ b/Uebung 3/Uebung3_3/extendedgraph2.h @@ -0,0 +1,72 @@ +#include /* cout, cerr */ +#include /* INT_MAX */ +#include /* type stringstream to easily concat a result string */ +#include /* type string */ +#include /* type vector */ + +#include "edge.h" + +#pragma once + +void vectorToString(std::vector vector); + +/* -- Class Graph -- */ +class ExtendedGraph { +private: + std::vector vertices; // vector connecting vertices with + // indicies; needed for name resolution + + std::vector visited = {false}; + +public: + ExtendedGraph(); // default constructor + ExtendedGraph(const std::vector &vertices, + const std::vector &edges); // param. constructor + std::vector> + adjacencyMatrix; // vector of vectors containing integers (the adjacency + // matrix) + + /* -- + Resolves a given string of a vertex and returns its position in the + adjacencyMatrix (as integer). Returns -1 if name could not be resolved, + which indicates the the name was not found. + -- */ + int resolveVertex(const std::string &name); + void + printGraph(); // prints out the graph with vertices and the adjacencyMatrix + + /* -- + Graph Manipulation Functions + -- */ + void insertVertex( + const std::string &vertex); // inserts a new vertex; throws error, if + // vertex already exists in Graph + void deleteVertex( + const std::string &vertex); // deletes a vertex from the Graph; throws an + // error, if vertex does not exist + void insertEdge( + const Edge &edge); // inserts a new edge; parameter can be {std::string, + // std::string} due to implicit cast... + // ...does not check if the edge already exists, nor + // notifies user/programmer + void deleteEdge( + const Edge &edge); // deletes an edge; parameter can be {std::string, + // std::string} due to implicit cast... + // ...does not check if edge exists + bool adjacent(const std::string &vertex1, + const std::string + &vertex2); // checks if vertex1 and vertex2 are adjacent; + // returns boolean; adjacency indicates that... + // ...a direct connection between a <--> b + // (direction NOT important) exists + std::vector + neighbours(const std::string + &vertex); // returns a vector of strings, containing all + // neighbouring vertices of the parameter vertex... + // ...Neighbours are all vertices that a given + // vertex is connected to through OUTGOING edges + + int getEdgeWeight(std::string sourceVertex, std::string targetVertex); + void setEdgeWeight(std::string sourceVertex, std::string targetVertex, + int weight); +}; \ No newline at end of file diff --git a/Uebung 3/Uebung3_3/main.cpp b/Uebung 3/Uebung3_3/main.cpp new file mode 100644 index 0000000..09ab4ae --- /dev/null +++ b/Uebung 3/Uebung3_3/main.cpp @@ -0,0 +1,75 @@ + +#include "edge.h" +#include "extendedgraph2.h" +#include /* cout, cerr */ +#include /* type stringstream to easily concat a result string */ +#include /* type string */ +#include /* type vector */ + +int main() { + /* Creation of Graph */ + std::vector vertices = { + "London", "Mailand", "Wien", "Madrid", "Rom", + "Paris", "Amsterdam", "Moskau", "Berlin", "Lyon"}; + std::vector edges = { + {"London", "Mailand", 2}, {"London", "Wien", 2}, + {"Mailand", "London", 2}, {"Mailand", "Wien", 6}, + {"Mailand", "Madrid", 5}, {"Wien", "London", 2}, + {"Wien", "Mailand", 6}, {"Wien", "Rom", 4}, + {"Wien", "Paris", 5}, {"Madrid", "Mailand", 5}, + {"Madrid", "Rom", 5}, {"Madrid", "Lyon", 3}, + {"Rom", "Wien", 4}, {"Rom", "Madrid", 5}, + {"Rom", "Moskau", 3}, {"Rom", "Lyon", 4}, + {"Amsterdam", "Paris", 1}, {"Amsterdam", "Moskau", 1}, + {"Moskau", "Rom", 3}, {"Moskau", "Paris", 1}, + {"Moskau", "Amsterdam", 1}, {"Moskau", "Berlin", 2}, + {"Berlin", "Moskau", 2}, {"Berlin", "Lyon", 2}, + {"Lyon", "Madrid", 3}, {"Lyon", "Rom", 4}, + {"Lyon", "Paris", 2}, {"Lyon", "Berlin", 2}}; + ExtendedGraph g(vertices, edges); + g.printGraph(); + std::cout << g.getEdgeWeight("Amsterdam", "London") << std::endl; + g.setEdgeWeight("Amsterdam", "London", 12); + std::cout << g.getEdgeWeight("Amsterdam", "London") << std::endl; + + /* insertVertices */ + // g.insertVertex("D"); + // g.insertVertex("H"); + // g.printGraph(); + + /* insertEdges */ + // g.insertEdge({"C", "D"}); + // g.insertEdge({"F", "H"}); + // g.insertEdge({"G", "H"}); + // g.insertEdge({"D", "H"}); + // g.printGraph(); + + /* deleteEdges */ + // g.deleteEdge({"D", "H"}); + // g.printGraph(); + + /* Delete Vertices */ + // g.deleteVertex("C"); + // g.printGraph(); + + /* Adjacency */ + // std::cout << "Adjacent B --> A? " << g.adjacent("B", "A") << "\n"; + // std::cout << "Adjacent A --> B? " << g.adjacent("A", "B") << "\n"; + // std::cout << "Adjacent A --> H? " << g.adjacent("A", "H") << "\n"; + + /* Neighbourhood */ + // std::cout << "\n"; + // std::cout << "Neighbours of B: "; + // vectorToString(g.neighbours("B")); + // std::cout << "Neighbours of A: "; + // vectorToString(g.neighbours("A")); + // std::cout << "Neighbours of H: "; + // vectorToString(g.neighbours("H")); +} + +void vectorToString(std::vector vector) { + for (int i = 0; i < vector.size(); i++) { + std::cout << vector[i] << "\t"; + } + std::cout << "\n"; +}