Init
This commit is contained in:
BIN
P4/ADS_Praktikum_4.pdf
Executable file
BIN
P4/ADS_Praktikum_4.pdf
Executable file
Binary file not shown.
12
P4/CMakeLists.txt
Executable file
12
P4/CMakeLists.txt
Executable file
@@ -0,0 +1,12 @@
|
||||
# Set the minimum required version of CMake
|
||||
cmake_minimum_required(VERSION 3.11)
|
||||
|
||||
# Set the project name and specify the C++ as the project language
|
||||
project(P4_Graph)
|
||||
|
||||
# Specify the C++ standard
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Add an executable with the above sources
|
||||
add_executable(P4_Graph main.cpp DijkstraSP.cpp EdgeWeightedDigraph.cpp EdgeWeightedGraph.cpp GraphTest.cpp KruskalMST.cpp PrimMST.cpp)
|
||||
95
P4/DijkstraSP.cpp
Executable file
95
P4/DijkstraSP.cpp
Executable file
@@ -0,0 +1,95 @@
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <algorithm>
|
||||
#include "DijkstraSP.h"
|
||||
|
||||
/**
|
||||
* F<>ge eine Kante mit minimalen Kosten hinzu, die von einem
|
||||
* Baumknoten zu einem Nicht-Baumknoten verl<72>uft und deren
|
||||
* Ziel w dem Startknoten s am n<>chsten ist.
|
||||
*
|
||||
* \param[in] G Kantengewichteter-Digraph
|
||||
* \param[in] v Zielknoten
|
||||
*/
|
||||
void DijkstraSP::relax(EdgeWeightedDigraph G, int v) {
|
||||
std::vector<DirectedEdge> edges = G[v]; //adjazente Knoten zum Knoten v
|
||||
for (DirectedEdge e: edges) {
|
||||
int w = e.to();
|
||||
if (distToVect[w] > distToVect[v] + e.weight()) {
|
||||
distToVect[w] = distToVect[v] + e.weight();
|
||||
edgeTo[w] = e;
|
||||
if (pq.contains(w))
|
||||
pq.change(w, distToVect[v]);
|
||||
else
|
||||
pq.push(w, distToVect[w]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuert den Dijkstra Algorithmus von s, im Graph G aus.
|
||||
*
|
||||
* \param[in] G Kantengewichteter-Digraph
|
||||
* \param[in] s Startknoten
|
||||
*/
|
||||
DijkstraSP::DijkstraSP(EdgeWeightedDigraph G, int s) {
|
||||
//Initialisiere distToVect mit "unendlich"
|
||||
distToVect.resize(G.getV());
|
||||
for (int v = 0; v < G.getV(); v++) {
|
||||
distToVect[v] = DBL_MAX;
|
||||
}
|
||||
//Setze die Kosten f<>r Startknoten auf 0
|
||||
distToVect[s] = 0.0;
|
||||
|
||||
pq.push(s, 0.0);
|
||||
//F?ge immer eine Kante mit minimalen Pfadkosten zu s hinzu
|
||||
while (!pq.empty()) {
|
||||
int min_node = pq.top().value;
|
||||
pq.pop();
|
||||
|
||||
//F?ge immer eine Kante mit minimalen Pfadkosten zu s der PQ hinzu
|
||||
relax(G, min_node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Distanz von s zum Knoten v zurueck
|
||||
*
|
||||
* \param[in] v Zielknoten
|
||||
* \return Summe der Gewichte auf dem Pfad zu v
|
||||
*/
|
||||
double DijkstraSP::distTo(int v) const {
|
||||
return distToVect[v];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt zurueck ob es einen Pfad zu v von s aus gibt
|
||||
*
|
||||
* \param[in] v Zielknoten
|
||||
* \return true, wenn es einen Pfad von s nach v gibt, sonst false
|
||||
*/
|
||||
bool DijkstraSP::hasPathTo(int v) const {
|
||||
if (distToVect[v] == DBL_MAX)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Pfad von s nach v als Vektor zurueck
|
||||
*
|
||||
* \param[in] v Zielknoten
|
||||
* \return Vektor mit allen Kanten des Pfades von s nach v
|
||||
*/
|
||||
std::vector<DirectedEdge> DijkstraSP::pathTo(int v) {
|
||||
std::vector<DirectedEdge> path;
|
||||
DirectedEdge e = edgeTo[v];
|
||||
|
||||
while (true) {
|
||||
path.push_back(e);
|
||||
if (edgeTo.count(e.from()) > 0) {
|
||||
e = edgeTo[e.from()];
|
||||
} else break;
|
||||
}
|
||||
std::reverse(path.begin(), path.end());
|
||||
return path;
|
||||
}
|
||||
25
P4/DijkstraSP.h
Executable file
25
P4/DijkstraSP.h
Executable file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
#include "EdgeWeightedDigraph.h"
|
||||
#include "PriorityQueue.h"
|
||||
|
||||
class DijkstraSP {
|
||||
private:
|
||||
std::map<int, DirectedEdge> edgeTo;
|
||||
std::vector<double> distToVect;
|
||||
Utils::PriorityQueue<int> pq;
|
||||
|
||||
void relax(EdgeWeightedDigraph G, int v);
|
||||
|
||||
public:
|
||||
DijkstraSP() {
|
||||
};
|
||||
|
||||
DijkstraSP(EdgeWeightedDigraph G, int s);
|
||||
|
||||
double distTo(int v) const; // Abst<73>nde vom Startvertex zu v
|
||||
bool hasPathTo(int v) const; // <20>berpr<70>ft die existens eines Pfades
|
||||
std::vector<DirectedEdge> pathTo(int v); // Kanten des k<>rzsesten Weges
|
||||
};
|
||||
163
P4/EdgeWeightedDigraph.cpp
Executable file
163
P4/EdgeWeightedDigraph.cpp
Executable file
@@ -0,0 +1,163 @@
|
||||
#include <assert.h>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include "EdgeWeightedDigraph.h"
|
||||
|
||||
/**
|
||||
* Gibt zurueck ob der Knoten v ein gueltiger Knoten im Graph ist
|
||||
*
|
||||
* \param[in] v Knoten
|
||||
* \return Gueltigkeit des Knoten
|
||||
*/
|
||||
bool EdgeWeightedDigraph::validateVertex(int v) const {
|
||||
return v >= 0 && v < this->V;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt eine Fehlermeldung aus, wenn der Knoten v im Graph nicht gueltig ist
|
||||
*
|
||||
* \param[in] v Knoten
|
||||
*/
|
||||
void EdgeWeightedDigraph::validateVertexWithError(int v) const {
|
||||
assert(("Vertex is out of bounds!", this->validateVertex(v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen Kantengewichteten-Gaph mit V Knoten
|
||||
*
|
||||
* \param[in] V Anzahl der Knoten
|
||||
*/
|
||||
EdgeWeightedDigraph::EdgeWeightedDigraph(int V)
|
||||
: V{V}
|
||||
, E{0} {
|
||||
adj.resize(V);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen Kantengewichteten-Gaph anhand der Kantenliste in fname
|
||||
*
|
||||
* \param[in] fname Dateiname der Kantenliste
|
||||
*/
|
||||
EdgeWeightedDigraph::EdgeWeightedDigraph(std::string filename) {
|
||||
std::ifstream infile(filename);
|
||||
int tmp_e = 0;
|
||||
infile >> this->V >> tmp_e;
|
||||
|
||||
this->E = 0;
|
||||
|
||||
this->adj.resize(this->V, std::vector<DirectedEdge>());
|
||||
|
||||
int v, w;
|
||||
double weight;
|
||||
while (infile >> v >> w >> weight) {
|
||||
this->add(DirectedEdge(v, w, weight));
|
||||
}
|
||||
|
||||
assert(("Missing edges!", tmp_e == this->E));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuegt die Kante e zum Graphen hinzu
|
||||
*
|
||||
* \param[in] e Kante
|
||||
*/
|
||||
void EdgeWeightedDigraph::add(DirectedEdge e) {
|
||||
this->validateVertexWithError(e.from());
|
||||
this->validateVertexWithError(e.to());
|
||||
|
||||
this->adj[e.from()].push_back(e);
|
||||
|
||||
this->E++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Anzahl der Knoten zurueck
|
||||
*
|
||||
* \return Anzahl der Knoten
|
||||
*/
|
||||
int EdgeWeightedDigraph::getV() const {
|
||||
return this->V;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Anzahl der Kanten zurueck
|
||||
*
|
||||
* \return Anzahl der Kanten
|
||||
*/
|
||||
int EdgeWeightedDigraph::getE() const {
|
||||
return this->E;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert alle benachbarten Kanten zu v
|
||||
*
|
||||
* \param[in] v Knoten von dem aus gesucht wird
|
||||
* \return Vektor mit allen benachbarten Kanten
|
||||
*/
|
||||
std::vector<std::vector<DirectedEdge> > EdgeWeightedDigraph::getAdj() const {
|
||||
return this->adj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert alle benachbarten Kanten zu v
|
||||
*
|
||||
* \param[in] v Knoten von dem aus gesucht wird
|
||||
* \return Vektor mit allen benachbarten Kanten
|
||||
*/
|
||||
std::vector<DirectedEdge> EdgeWeightedDigraph::getAdj(int v) const {
|
||||
std::vector<DirectedEdge> neighbors;
|
||||
for (auto const &n: adj[v]) {
|
||||
neighbors.push_back(n);
|
||||
}
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle Kanten im Graph zurueck
|
||||
*
|
||||
* \return Vektor mit allen Kanten im Graph
|
||||
*/
|
||||
std::vector<DirectedEdge> EdgeWeightedDigraph::edges() const {
|
||||
std::vector<DirectedEdge> list;
|
||||
for (int v = 0; v < this->V; v++) {
|
||||
for (DirectedEdge e: this->adj[v]) {
|
||||
list.push_back(e);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
bool EdgeWeightedDigraph::del_Edge(DirectedEdge e) {
|
||||
int from = e.from();
|
||||
int to = e.to();
|
||||
|
||||
// ?berpr?fen, ob die Knoten g?ltig sind
|
||||
if (!validateVertex(from) || !validateVertex(to)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Suchen und Entfernen der Kante aus der Adjazenzliste des Ausgangsknotens
|
||||
std::vector<DirectedEdge> &adj_from = adj[from];
|
||||
for (auto it = adj_from.begin(); it != adj_from.end(); ++it) {
|
||||
if (*it == e) {
|
||||
adj_from.erase(it);
|
||||
E--; // Verringern der Gesamtzahl der Kanten
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Kante wurde nicht gefunden
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Kantenliste eines Knoten v zurueck
|
||||
*
|
||||
* \param[in] v Knoten
|
||||
* \return Vektor mit den Kanten vom Knoten v
|
||||
*/
|
||||
const std::vector<DirectedEdge> EdgeWeightedDigraph::operator[](int from) const {
|
||||
return this->adj[from];
|
||||
}
|
||||
56
P4/EdgeWeightedDigraph.h
Executable file
56
P4/EdgeWeightedDigraph.h
Executable file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class DirectedEdge {
|
||||
private:
|
||||
int _from; // Startknoten
|
||||
int _to; // Endknoten
|
||||
double _weight; // Gewicht der Kante
|
||||
public:
|
||||
DirectedEdge()
|
||||
: _from{0}
|
||||
, _to{0}
|
||||
, _weight{0} {
|
||||
}
|
||||
|
||||
DirectedEdge(int from, int to, double weight)
|
||||
: _weight{weight}
|
||||
, _from{from}
|
||||
, _to{to} {
|
||||
}
|
||||
|
||||
double weight() const { return _weight; }
|
||||
int from() const { return _from; }
|
||||
int to() const { return _to; }
|
||||
};
|
||||
|
||||
inline bool operator==(const DirectedEdge &lhs, const DirectedEdge &rhs) { return lhs.weight() == rhs.weight(); }
|
||||
inline bool operator!=(const DirectedEdge &lhs, const DirectedEdge &rhs) { return !operator==(lhs, rhs); }
|
||||
inline bool operator<(const DirectedEdge &lhs, const DirectedEdge &rhs) { return lhs.weight() < rhs.weight(); }
|
||||
inline bool operator>(const DirectedEdge &lhs, const DirectedEdge &rhs) { return operator<(rhs, lhs); }
|
||||
inline bool operator<=(const DirectedEdge &lhs, const DirectedEdge &rhs) { return !operator>(lhs, rhs); }
|
||||
inline bool operator>=(const DirectedEdge &lhs, const DirectedEdge &rhs) { return !operator<(lhs, rhs); }
|
||||
|
||||
class EdgeWeightedDigraph {
|
||||
private:
|
||||
int V; // Anzahl Knoten von G
|
||||
int E; // Anzahl Kanten von G
|
||||
std::vector<std::vector<DirectedEdge> > adj; // Adjazenzliste
|
||||
bool validateVertex(int v) const;
|
||||
|
||||
void validateVertexWithError(int v) const;
|
||||
|
||||
public:
|
||||
EdgeWeightedDigraph(int V); // Leeren Digraphen mit v Knoten erstellen
|
||||
EdgeWeightedDigraph(std::string filename); // Graph einlesen aus Textdatei
|
||||
void add(DirectedEdge e); // gerichtete Kante hinzuf<75>gen
|
||||
int getV() const; // liefert Anzahl Knoten
|
||||
int getE() const; // liefert Anzahl der Kanten
|
||||
std::vector<std::vector<DirectedEdge> > getAdj() const; // liefert die gestamte Kantenliste
|
||||
std::vector<DirectedEdge> getAdj(int v) const; // liefert Array der adjazenten Kanten zu v
|
||||
std::vector<DirectedEdge> edges() const; // alle Kanten dieses Graphen
|
||||
const std::vector<DirectedEdge> operator[](int v) const;
|
||||
|
||||
bool del_Edge(DirectedEdge e); // L<>scht eine Kante
|
||||
};
|
||||
197
P4/EdgeWeightedGraph.cpp
Executable file
197
P4/EdgeWeightedGraph.cpp
Executable file
@@ -0,0 +1,197 @@
|
||||
#include "EdgeWeightedGraph.h"
|
||||
#include <fstream>
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* Erstellt einen Kantengewichteten-Gaph mit V Knoten
|
||||
*
|
||||
* \param[in] V Anzahl der Knoten
|
||||
*/
|
||||
EdgeWeightedGraph::EdgeWeightedGraph(int V)
|
||||
: V{V}
|
||||
, E{0} {
|
||||
adj.resize(V);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen Kantengewichteten-Gaph anhand der Kantenliste in fname
|
||||
*
|
||||
* \param[in] fname Dateiname der Kantenliste
|
||||
*/
|
||||
EdgeWeightedGraph::EdgeWeightedGraph(std::string filename) {
|
||||
std::ifstream infile(filename);
|
||||
int tmp_e = 0;
|
||||
infile >> this->V >> tmp_e;
|
||||
|
||||
this->E = 0;
|
||||
|
||||
this->adj.resize(this->V, std::vector<Edge>());
|
||||
|
||||
int v, w;
|
||||
double weight;
|
||||
while (infile >> v >> w >> weight) {
|
||||
this->add(Edge(v, w, weight));
|
||||
}
|
||||
|
||||
assert(("Missing edges!", tmp_e == this->E));
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen Kantengewichteten-Gaph mit V Knoten und den Kanten in edges
|
||||
*
|
||||
* \param[in] V Anzahl der Knoten
|
||||
* \param[in] E Kantenliste
|
||||
*/
|
||||
EdgeWeightedGraph::EdgeWeightedGraph(int V, std::vector<Edge> E) {
|
||||
this->V = V;
|
||||
this->adj.resize(V);
|
||||
|
||||
for (Edge e: E) {
|
||||
this->add(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt zurueck ob der Knoten v ein gueltiger Knoten im Graph ist
|
||||
*
|
||||
* \param[in] v Knoten
|
||||
* \return Gueltigkeit des Knoten
|
||||
*/
|
||||
bool EdgeWeightedGraph::validateVertex(int v) const {
|
||||
return v >= 0 && v < this->V;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt eine Fehlermeldung aus, wenn der Knoten v im Graph nicht gueltig ist
|
||||
*
|
||||
* \param[in] v Knoten
|
||||
*/
|
||||
void EdgeWeightedGraph::validateVertexWithError(int v) const {
|
||||
assert(("Vertex is out of bounds!", this->validateVertex(v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Anzahl der Knoten zurueck
|
||||
*
|
||||
* \return Anzahl der Knoten
|
||||
*/
|
||||
int EdgeWeightedGraph::getV() const {
|
||||
return this->V;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Anzahl der Kanten zurueck
|
||||
*
|
||||
* \return Anzahl der Kanten
|
||||
*/
|
||||
int EdgeWeightedGraph::getE() const {
|
||||
return this->E;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuegt die Kante e zum Graphen hinzu
|
||||
*
|
||||
* \param[in] e neue Kante
|
||||
*/
|
||||
void EdgeWeightedGraph::add(Edge e) {
|
||||
this->validateVertexWithError(e.either());
|
||||
this->validateVertexWithError(e.other(e.either()));
|
||||
|
||||
this->adj[e.either()].push_back(e);
|
||||
this->adj[e.other(e.either())].push_back(e);
|
||||
|
||||
this->E++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert alle benachbarten Kanten zu v
|
||||
*
|
||||
* \param[in] v Knoten von dem aus gesucht wird
|
||||
* \return Vektor mit allen benachbarten Kanten
|
||||
*/
|
||||
std::vector<Edge> EdgeWeightedGraph::getAdj(int v) const {
|
||||
std::vector<Edge> neighbors;
|
||||
for (auto const &n: adj[v]) {
|
||||
neighbors.push_back(n);
|
||||
}
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
std::vector<std::vector<Edge> > EdgeWeightedGraph::getAdj() const {
|
||||
return this->adj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle Kanten im Graph zurueck
|
||||
*
|
||||
* \return Vektor mit allen Kanten im Graph
|
||||
*/
|
||||
std::vector<Edge> EdgeWeightedGraph::edges() const {
|
||||
std::vector<Edge> edgeList;
|
||||
for (int v = 0; v < this->V; v++) {
|
||||
int selfLoops = 0;
|
||||
for (Edge e: this->adj[v]) {
|
||||
if (e.other(v) > v) {
|
||||
edgeList.push_back(e);
|
||||
}
|
||||
// add only one copy of each self loop (self loops will be consecutive)
|
||||
else if (e.other(v) == v) {
|
||||
if (selfLoops % 2 == 0) edgeList.push_back(e);
|
||||
selfLoops++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return edgeList;
|
||||
}
|
||||
|
||||
bool EdgeWeightedGraph::del_Edge(Edge e) {
|
||||
int v = e.either();
|
||||
int w = e.other(v);
|
||||
|
||||
// Überprüfen, ob die Knoten gültig sind
|
||||
if (!validateVertex(v) || !validateVertex(w)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool removed = false;
|
||||
|
||||
// Entfernen der Kante von v zu w
|
||||
std::vector<Edge> &adj_v = adj[v];
|
||||
for (auto it = adj_v.begin(); it != adj_v.end(); ++it) {
|
||||
if (*it == e) {
|
||||
adj_v.erase(it);
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Entfernen der Kante von w zu v (falls es sich nicht um eine Schlinge handelt)
|
||||
if (v != w) {
|
||||
std::vector<Edge> &adj_w = adj[w];
|
||||
for (auto it = adj_w.begin(); it != adj_w.end(); ++it) {
|
||||
if (*it == e) {
|
||||
adj_w.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wenn die Kante entfernt wurde, verringern wir die Kantenanzahl
|
||||
if (removed) {
|
||||
E--;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die verbunden Knoten eines Knoten v zurueck
|
||||
*
|
||||
* \param[in] v Knoten
|
||||
* \return Verbundene Knoten des Knoten v
|
||||
*/
|
||||
const std::vector<Edge> EdgeWeightedGraph::operator[](int v) const {
|
||||
this->validateVertexWithError(v);
|
||||
return this->adj[v];
|
||||
}
|
||||
60
P4/EdgeWeightedGraph.h
Executable file
60
P4/EdgeWeightedGraph.h
Executable file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iomanip>
|
||||
|
||||
class Edge {
|
||||
private:
|
||||
int _either; // ein Knoten der Kante
|
||||
int _other; // der andere Knoten der Kante
|
||||
double _weight; // Kantengewicht
|
||||
public:
|
||||
Edge(int either, int other, double weight)
|
||||
: _either{either}
|
||||
, _other{other}
|
||||
, _weight{weight} {
|
||||
}
|
||||
|
||||
double weight() const { return _weight; } // Gewicht dieser Kante
|
||||
int either() const { return _either; } // einer der beiden Knoten
|
||||
int other(int vertex) const {
|
||||
// der von "vertex" verschiedene Knoten
|
||||
if (vertex == _either) return _other;
|
||||
else if (vertex == _other) return _either;
|
||||
else throw new std::invalid_argument("Illegal endpoint");
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const Edge &lhs, const Edge &rhs) { return lhs.weight() == rhs.weight(); }
|
||||
inline bool operator!=(const Edge &lhs, const Edge &rhs) { return !operator==(lhs, rhs); }
|
||||
inline bool operator<(const Edge &lhs, const Edge &rhs) { return lhs.weight() < rhs.weight(); }
|
||||
inline bool operator>(const Edge &lhs, const Edge &rhs) { return operator<(rhs, lhs); }
|
||||
inline bool operator<=(const Edge &lhs, const Edge &rhs) { return !operator>(lhs, rhs); }
|
||||
inline bool operator>=(const Edge &lhs, const Edge &rhs) { return !operator<(lhs, rhs); }
|
||||
|
||||
|
||||
class EdgeWeightedGraph {
|
||||
private:
|
||||
int V; // Anzahl Knoten von G
|
||||
int E; // Anzahl Kanten von G
|
||||
std::vector<std::vector<Edge> > adj; // Adjazenzliste
|
||||
bool validateVertex(int v) const;
|
||||
|
||||
void validateVertexWithError(int v) const;
|
||||
|
||||
public:
|
||||
EdgeWeightedGraph(int V); // Leeren Graph mit v Knoten erstellen
|
||||
EdgeWeightedGraph(std::string filename); // Graph einlesen aus Textdatei
|
||||
EdgeWeightedGraph(int V, std::vector<Edge> E);
|
||||
|
||||
void add(Edge e); // f<>gt Kante e dem Graphen hinzu
|
||||
int getV() const; // liefert Anzahl Knoten
|
||||
int getE() const; // liefert Anzahl der Kanten
|
||||
std::vector<Edge> getAdj(int v) const; // liefert Array der adjazenten Kanten zu v
|
||||
std::vector<std::vector<Edge> > getAdj() const;
|
||||
|
||||
std::vector<Edge> edges() const; // alle Kanten dieses Graphen
|
||||
bool del_Edge(Edge e);
|
||||
|
||||
const std::vector<Edge> operator[](int v) const;
|
||||
};
|
||||
417
P4/GraphTest.cpp
Executable file
417
P4/GraphTest.cpp
Executable file
@@ -0,0 +1,417 @@
|
||||
/*************************************************
|
||||
* ADS Praktikum 5
|
||||
* Unit-Testdatei
|
||||
* Stand: 01.06.2021
|
||||
*
|
||||
*************************************************
|
||||
* Änderungen untersagt!
|
||||
*************************************************/
|
||||
#include "catch.hpp"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include "EdgeWeightedGraph.h"
|
||||
#include "EdgeWeightedDigraph.h"
|
||||
#include "DijkstraSP.h"
|
||||
#include "KruskalMST.h"
|
||||
#include "PrimMST.h"
|
||||
|
||||
namespace Graphsearch {
|
||||
bool DFS(const EdgeWeightedGraph& G, int v, std::vector<bool>& marked, std::vector<int>& edgeTo);
|
||||
bool BFS(const EdgeWeightedGraph& G, int v, std::vector<bool>& marked, std::vector<int>& edgeTo);
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Testroutine des Graphen:
|
||||
- Adjazenzlisten
|
||||
- Tiefensuche mit zusammenhängenden Graphen
|
||||
- Tiefensuche mit nicht zusammenhängenden Graphen
|
||||
- Breitensuche mit zusammenhängenden Graphen
|
||||
- Breitensuche mit nicht zusammenhängenden Graphen
|
||||
- Prim mit bestimmten Ergebnissen
|
||||
- Kruskal mit bestimmten Ergebnissen
|
||||
- Dijkstra
|
||||
*/
|
||||
TEST_CASE("Graph Test: Adjazenzliste") {
|
||||
EdgeWeightedGraph G1("graph1.txt");
|
||||
EdgeWeightedGraph G2("graph2.txt");
|
||||
EdgeWeightedGraph G3("graph3.txt");
|
||||
|
||||
SECTION("Adjazenzliste des ersten Graphen (graph1.txt)") {
|
||||
REQUIRE(G1.getV() == 7);
|
||||
REQUIRE(G1.getE() == 11);
|
||||
|
||||
auto adj = G1.getAdj();
|
||||
REQUIRE(adj[0][0].either() == 0);
|
||||
REQUIRE(adj[0][0].other(0) == 1);
|
||||
REQUIRE(adj[0][0].weight() == 7.0);
|
||||
|
||||
REQUIRE(adj[4][3].either() == 4);
|
||||
REQUIRE(adj[4][3].other(4) == 5);
|
||||
REQUIRE(adj[4][3].weight() == 8.0);
|
||||
}
|
||||
|
||||
SECTION("Adjazenzliste des zweiten Graphen (graph2.txt)") {
|
||||
REQUIRE(G2.getV() == 20);
|
||||
REQUIRE(G2.getE() == 60);
|
||||
|
||||
auto adj = G2.getAdj();
|
||||
REQUIRE(adj[0][0].either() == 0);
|
||||
REQUIRE(adj[0][0].other(0) == 1);
|
||||
REQUIRE(adj[0][0].weight() == 6.0);
|
||||
|
||||
REQUIRE(adj[13][5].either() == 13);
|
||||
REQUIRE(adj[13][5].other(13) == 19);
|
||||
REQUIRE(adj[13][5].weight() == 25.0);
|
||||
}
|
||||
|
||||
SECTION("Adjazenzliste des dritten Graphen (graph3.txt)") {
|
||||
REQUIRE(G2.getV() == 20);
|
||||
REQUIRE(G2.getE() == 60);
|
||||
|
||||
auto adj = G2.getAdj();
|
||||
REQUIRE(adj[0][0].either() == 0);
|
||||
REQUIRE(adj[0][0].other(0) == 1);
|
||||
REQUIRE(adj[0][0].weight() == 6.0);
|
||||
|
||||
REQUIRE(adj[13][5].either() == 13);
|
||||
REQUIRE(adj[13][5].other(13) == 19);
|
||||
REQUIRE(adj[13][5].weight() == 25.0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Graph Test: Tiefensuche (DFS)") {
|
||||
|
||||
EdgeWeightedGraph G1("graph1.txt");
|
||||
EdgeWeightedGraph G2("graph2.txt");
|
||||
EdgeWeightedGraph G3("graph3.txt");
|
||||
|
||||
std::vector<bool> marked;
|
||||
std::vector<int> edgeTo;
|
||||
|
||||
SECTION("Tiefensuche mit erstem Graphen (graph1.txt") {
|
||||
marked.resize(42, false); // Dummy values, damit die unit-Tests mit
|
||||
edgeTo.resize(42, -1); // der Vorlage durchlaufen ohne Programmabsturz
|
||||
|
||||
for (int i = 0; i < G1.getV(); i++) {
|
||||
bool connected = Graphsearch::DFS(G1, i, marked, edgeTo);
|
||||
REQUIRE(connected == true);
|
||||
}
|
||||
|
||||
// edgeTo-Array der Tiefensuche mit Startknoten 0 testen
|
||||
Graphsearch::DFS(G1, 0, marked, edgeTo);
|
||||
REQUIRE(edgeTo.size() == G1.getV());
|
||||
REQUIRE(marked.size() == G1.getV());
|
||||
REQUIRE(edgeTo[0] == -1);
|
||||
REQUIRE(edgeTo[1] == 0);
|
||||
REQUIRE(edgeTo[2] == 1);
|
||||
REQUIRE(edgeTo[3] == 4);
|
||||
REQUIRE(edgeTo[4] == 2);
|
||||
REQUIRE(edgeTo[5] == 3);
|
||||
REQUIRE(edgeTo[6] == 5);
|
||||
}
|
||||
|
||||
SECTION("Tiefensuche mit zweiten Graphen (graph2.txt)") {
|
||||
marked.resize(42, false); // Dummy values, damit die unit-Tests mit
|
||||
edgeTo.resize(42, -1); // der Vorlage durchlaufen ohne Programmabsturz
|
||||
|
||||
for (int i = 0; i < G2.getV(); i++) {
|
||||
bool connected = Graphsearch::DFS(G2, i, marked, edgeTo);
|
||||
REQUIRE(connected == true);
|
||||
}
|
||||
|
||||
Graphsearch::DFS(G2, 0, marked, edgeTo);
|
||||
REQUIRE(edgeTo.size() == G2.getV());
|
||||
REQUIRE(marked.size() == G2.getV());
|
||||
REQUIRE(edgeTo[0] == -1);
|
||||
REQUIRE(edgeTo[1] == 0);
|
||||
REQUIRE(edgeTo[7] == 4);
|
||||
REQUIRE(edgeTo[8] == 9);
|
||||
REQUIRE(edgeTo[19] == 13);
|
||||
}
|
||||
|
||||
SECTION("Tiefensuche mit dritten Graphen (graph3.txt)") {
|
||||
marked.resize(42, false); // Dummy values, damit die unit-Tests mit
|
||||
edgeTo.resize(42, -1); // der Vorlage durchlaufen ohne Programmabsturz
|
||||
|
||||
for (int i = 0; i < G3.getV(); i++) {
|
||||
bool connected = Graphsearch::DFS(G3, i, marked, edgeTo);
|
||||
REQUIRE(connected == false);
|
||||
}
|
||||
|
||||
Graphsearch::DFS(G3, 0, marked, edgeTo);
|
||||
REQUIRE(edgeTo.size() == G3.getV());
|
||||
REQUIRE(marked.size() == G3.getV());
|
||||
REQUIRE(marked[0] == true);
|
||||
REQUIRE(marked[4] == true);
|
||||
REQUIRE(marked[18] == true);
|
||||
|
||||
Graphsearch::DFS(G3, 1, marked, edgeTo);
|
||||
REQUIRE(edgeTo.size() == G3.getV());
|
||||
REQUIRE(marked.size() == G3.getV());
|
||||
REQUIRE(marked[0] == false);
|
||||
REQUIRE(marked[4] == false);
|
||||
REQUIRE(marked[18] == false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Graph Test: Breitensuche (BFS)") {
|
||||
|
||||
EdgeWeightedGraph G1("graph1.txt");
|
||||
EdgeWeightedGraph G2("graph2.txt");
|
||||
EdgeWeightedGraph G3("graph3.txt");
|
||||
|
||||
std::vector<bool> marked;
|
||||
std::vector<int> edgeTo;
|
||||
|
||||
SECTION("Breitensuche mit erstem Graphen (graph1.txt") {
|
||||
marked.resize(42, false); // Dummy values, damit die unit-Tests mit
|
||||
edgeTo.resize(42, -1); // der Vorlage durchlaufen ohne Programmabsturz
|
||||
|
||||
for (int i = 0; i < G1.getV(); i++) {
|
||||
bool connected = Graphsearch::BFS(G1, i, marked, edgeTo);
|
||||
REQUIRE(connected == true);
|
||||
}
|
||||
|
||||
// edgeTo-Array der Breitensuche mit Startknoten 0 testen
|
||||
Graphsearch::BFS(G1, 0, marked, edgeTo);
|
||||
REQUIRE(edgeTo.size() == G1.getV());
|
||||
REQUIRE(marked.size() == G1.getV());
|
||||
REQUIRE(edgeTo[0] == -1);
|
||||
REQUIRE(edgeTo[1] == 0);
|
||||
REQUIRE(edgeTo[2] == 1);
|
||||
REQUIRE(edgeTo[3] == 0);
|
||||
REQUIRE(edgeTo[4] == 1);
|
||||
REQUIRE(edgeTo[5] == 3);
|
||||
REQUIRE(edgeTo[6] == 4);
|
||||
}
|
||||
|
||||
SECTION("Breitensuche mit zweiten Graphen (graph2.txt)") {
|
||||
marked.resize(42, false); // Dummy values, damit die unit-Tests mit
|
||||
edgeTo.resize(42, -1); // der Vorlage durchlaufen ohne Programmabsturz
|
||||
|
||||
for (int i = 0; i < G2.getV(); i++) {
|
||||
bool connected = Graphsearch::BFS(G2, i, marked, edgeTo);
|
||||
REQUIRE(connected == true);
|
||||
}
|
||||
|
||||
// edgeTo-Array der Breitensuche mit Startknoten 0 testen
|
||||
Graphsearch::BFS(G2, 0, marked, edgeTo);
|
||||
REQUIRE(edgeTo.size() == G2.getV());
|
||||
REQUIRE(marked.size() == G2.getV());
|
||||
REQUIRE(edgeTo[0] == -1);
|
||||
REQUIRE(edgeTo[1] == 0);
|
||||
REQUIRE(edgeTo[2] == 3);
|
||||
REQUIRE(edgeTo[6] == 16);
|
||||
REQUIRE(edgeTo[11] == 4);
|
||||
REQUIRE(edgeTo[15] == 4);
|
||||
REQUIRE(edgeTo[19] == 0);
|
||||
}
|
||||
|
||||
SECTION("Breitensuche mit dritten Graphen (graph3.txt)") {
|
||||
marked.resize(42, false); // Dummy values, damit die unit-Tests mit
|
||||
edgeTo.resize(42, -1); // der Vorlage durchlaufen ohne Programmabsturz
|
||||
|
||||
for (int i = 0; i < G3.getV(); i++) {
|
||||
bool connected = Graphsearch::BFS(G3, i, marked, edgeTo);
|
||||
REQUIRE(edgeTo.size() == G3.getV());
|
||||
REQUIRE(marked.size() == G3.getV());
|
||||
REQUIRE(connected == false);
|
||||
|
||||
// Hinweis: Die Knoten {0,4,18} bilden einen Teilgraphen
|
||||
if (i == 0 || i == 4 || i == 18) {
|
||||
REQUIRE(marked[0] == true);
|
||||
REQUIRE(marked[4] == true);
|
||||
REQUIRE(marked[18] == true);
|
||||
}
|
||||
else {
|
||||
REQUIRE(marked[0] == false);
|
||||
REQUIRE(marked[4] == false);
|
||||
REQUIRE(marked[18] == false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Graph Test: Prim") {
|
||||
EdgeWeightedGraph G1("graph1.txt");
|
||||
EdgeWeightedGraph G2("graph2.txt");
|
||||
EdgeWeightedGraph G3("graph3.txt");
|
||||
|
||||
SECTION("Prim mit erstem Graph (graph1.txt)") {
|
||||
for (int i = 0; i < G1.getV(); i++) {
|
||||
PrimMST prim(G1, i);
|
||||
REQUIRE(prim.weight() == 39.0);
|
||||
|
||||
auto edges = prim.edges();
|
||||
REQUIRE(edges.size() == 6);
|
||||
std::vector<Edge> mst;
|
||||
mst.push_back(Edge(0, 3, 5.0));
|
||||
mst.push_back(Edge(2, 4, 5.0));
|
||||
mst.push_back(Edge(3, 5, 6.0));
|
||||
mst.push_back(Edge(1, 4, 7.0));
|
||||
mst.push_back(Edge(0, 1, 7.0));
|
||||
mst.push_back(Edge(4, 6, 9.0));
|
||||
|
||||
// Testen ob alle Edes des MST exitieren
|
||||
for (auto const& e : edges) {
|
||||
REQUIRE(std::find(mst.begin(), mst.end(), e) != mst.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Prim mit zweitem Graph (graph2.txt)") {
|
||||
for (int i = 0; i < G2.getV(); i++) {
|
||||
PrimMST prim(G2, i);
|
||||
REQUIRE(prim.weight() == 150.0);
|
||||
auto edges = prim.edges();
|
||||
REQUIRE(edges.size() == 19);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Prim mit drittem Graphen (graph3.txt)") {
|
||||
// Graph 3 mit Strartknoten 0
|
||||
PrimMST prim_0(G3, 0);
|
||||
REQUIRE(prim_0.weight() == 16.0);
|
||||
// Graph 3 mit Strartknoten 16
|
||||
PrimMST prim_16(G3, 16);
|
||||
REQUIRE(prim_16.weight() == 168.0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Graph Test: Kruskal") {
|
||||
EdgeWeightedGraph G1("graph1.txt");
|
||||
EdgeWeightedGraph G2("graph2.txt");
|
||||
EdgeWeightedGraph G3("graph3.txt");
|
||||
|
||||
SECTION("Kruskal mit erstem Graph (graph1.txt)") {
|
||||
KruskalMST kruskal(G1);
|
||||
REQUIRE(kruskal.weight() == 39.0);
|
||||
|
||||
auto edges = kruskal.edges();
|
||||
REQUIRE(edges.size() == 6);
|
||||
std::vector<Edge> mst;
|
||||
mst.push_back(Edge(0, 3, 5.0));
|
||||
mst.push_back(Edge(2, 4, 5.0));
|
||||
mst.push_back(Edge(3, 5, 6.0));
|
||||
mst.push_back(Edge(1, 4, 7.0));
|
||||
mst.push_back(Edge(0, 1, 7.0));
|
||||
mst.push_back(Edge(4, 6, 9.0));
|
||||
|
||||
// Testen ob alle Edes des MST exitieren
|
||||
for (auto const& e : edges) {
|
||||
REQUIRE(std::find(mst.begin(), mst.end(), e) != mst.end());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Kruskal mit zweitem Graph (graph2.txt)") {
|
||||
KruskalMST kruskal(G2);
|
||||
REQUIRE(kruskal.weight() == 150.0);
|
||||
REQUIRE(kruskal.edges().size() == 19);
|
||||
}
|
||||
|
||||
SECTION("Kruskal mit drittem Graph (graph3.txt)") {
|
||||
KruskalMST kruskal(G3);
|
||||
REQUIRE(kruskal.weight() == 184.0);
|
||||
REQUIRE(kruskal.edges().size() == 18);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Graph Test: Dijkstra") {
|
||||
EdgeWeightedDigraph G1_directed("graph1.txt");
|
||||
EdgeWeightedDigraph G2_directed("graph2.txt");
|
||||
EdgeWeightedDigraph G3_directed("graph3.txt");
|
||||
|
||||
int start, target;
|
||||
|
||||
SECTION("Dijkstra beim ersten Graph - 0 nach 6 (graph1.txt)") {
|
||||
start = 0;
|
||||
target = 6;
|
||||
DijkstraSP dsp(G1_directed, start);
|
||||
auto path = dsp.pathTo(target);
|
||||
|
||||
REQUIRE(dsp.distTo(target) == 22.0);
|
||||
REQUIRE(path.size() == 3);
|
||||
REQUIRE(path[0] == DirectedEdge(0, 3, 5.0));
|
||||
REQUIRE(path[1] == DirectedEdge(3, 5, 6.0));
|
||||
REQUIRE(path[2] == DirectedEdge(5, 6, 11.0));
|
||||
}
|
||||
|
||||
SECTION("Dijkstra beim ersten Graph - 2 nach 6 (graph1.txt)") {
|
||||
start = 2;
|
||||
target = 6;
|
||||
DijkstraSP dsp(G1_directed, start);
|
||||
auto path = dsp.pathTo(target);
|
||||
|
||||
REQUIRE(dsp.distTo(target) == 14.0);
|
||||
REQUIRE(path.size() == 2);
|
||||
REQUIRE(path[0] == DirectedEdge(2, 4, 5.0));
|
||||
REQUIRE(path[1] == DirectedEdge(4, 6, 9.0));
|
||||
}
|
||||
|
||||
SECTION("Dijkstra beim zweiten Graph - 0 nach 6 (graph2.txt)") {
|
||||
start = 0;
|
||||
target = 6;
|
||||
DijkstraSP dsp(G2_directed, start);
|
||||
auto path = dsp.pathTo(target);
|
||||
|
||||
REQUIRE(dsp.distTo(target) == 91.0);
|
||||
REQUIRE(path.size() == 3);
|
||||
REQUIRE(path[0] == DirectedEdge(0, 4, 47.0));
|
||||
REQUIRE(path[1] == DirectedEdge(4, 5, 36.0));
|
||||
REQUIRE(path[2] == DirectedEdge(5, 6, 8.0));
|
||||
}
|
||||
|
||||
SECTION("Dijkstra beim zweiten Graph - 3 nach 9 (graph2.txt)") {
|
||||
start = 3;
|
||||
target = 9;
|
||||
DijkstraSP dsp(G2_directed, start);
|
||||
auto path = dsp.pathTo(target);
|
||||
|
||||
REQUIRE(dsp.distTo(target) == 122.0);
|
||||
REQUIRE(path.size() == 4);
|
||||
REQUIRE(path[0] == DirectedEdge(3, 4, 46.0));
|
||||
REQUIRE(path[1] == DirectedEdge(4, 5, 36.0));
|
||||
REQUIRE(path[2] == DirectedEdge(5, 6, 8.0));
|
||||
REQUIRE(path[3] == DirectedEdge(6, 9, 32.0));
|
||||
}
|
||||
|
||||
SECTION("Dijkstra beim dritten Graph - 0 nach 4 (graph3.txt)") {
|
||||
start = 0;
|
||||
target = 4;
|
||||
DijkstraSP dsp(G3_directed, start);
|
||||
auto path = dsp.pathTo(target);
|
||||
|
||||
REQUIRE(dsp.distTo(target) == 47.0);
|
||||
REQUIRE(path.size() == 1);
|
||||
REQUIRE(path[0] == DirectedEdge(0, 4, 47.0));
|
||||
}
|
||||
|
||||
SECTION("Dijkstra beim dritten Graph - 1 nach 16 (graph3.txt)") {
|
||||
start = 1;
|
||||
target = 16;
|
||||
DijkstraSP dsp(G3_directed, start);
|
||||
auto path = dsp.pathTo(target);
|
||||
|
||||
REQUIRE(dsp.distTo(target) == 35.0);
|
||||
REQUIRE(path.size() == 2);
|
||||
REQUIRE(path[0] == DirectedEdge(1, 7, 9.0));
|
||||
REQUIRE(path[1] == DirectedEdge(7, 16, 26.0));
|
||||
}
|
||||
|
||||
SECTION("Dijkstra beim dritten Graph - 3 nach 7 (graph3.txt)") {
|
||||
start = 3;
|
||||
target = 7;
|
||||
DijkstraSP dsp(G3_directed, start);
|
||||
auto path = dsp.pathTo(target);
|
||||
|
||||
REQUIRE(dsp.distTo(target) == 42.0);
|
||||
REQUIRE(path.size() == 3);
|
||||
REQUIRE(path[0] == DirectedEdge(3, 5, 27.0));
|
||||
REQUIRE(path[1] == DirectedEdge(5, 6, 8.0));
|
||||
REQUIRE(path[2] == DirectedEdge(6, 7, 7.0));
|
||||
}
|
||||
}
|
||||
|
||||
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
// http://www.hashemall.com/
|
||||
// Zeile 1 - 413 hat den SHA 256 Hashwert: C812B068B2223D95AC8750EBBEB14261A7DFA84DF2DC4BC8F0026E7223C35A37
|
||||
101
P4/Graphsearch.h
Executable file
101
P4/Graphsearch.h
Executable file
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
#include "EdgeWeightedDigraph.h"
|
||||
#include "EdgeWeightedGraph.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace Graphsearch {
|
||||
/**
|
||||
* Fuehrt eine rekursive Tiefensuche im Graphen G,
|
||||
* ab dem Knoten v aus und markiert alle besuchten
|
||||
* Knoten in marked.
|
||||
* Alle besuchten Knoten werden ausgegeben.
|
||||
*
|
||||
* \param[in] G Graph
|
||||
* \param[in] v Startknoten
|
||||
* \param[in/out] marked Bereits besuchte Knoten
|
||||
* \param[in/out] edgeTo Vektor mit dem Nachfolgeknoten zu jedem Knoten
|
||||
*/
|
||||
void DFS_recursive(const EdgeWeightedGraph &G, int v, std::vector<bool> &marked, std::vector<int> &edgeTo) {
|
||||
std::cout << v;
|
||||
marked[v] = true;
|
||||
for (int j = 0; j < G.getAdj(v).size(); j++) {
|
||||
int w = G.getAdj(v)[j].other(v);
|
||||
if (marked[w] == false) {
|
||||
edgeTo[w] = v;
|
||||
std::cout << " -> ";
|
||||
DFS_recursive(G, w, marked, edgeTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuehrt eine rekursive Tiefensuche im Graphen g, ab dem Knoten v aus.
|
||||
* Alle besuchten Knoten werden ausgegeben.
|
||||
* Starterfunktion zu DFS_recursive(EdgeWeigtedGraph, int, std::vector<bool>, std::vector<int>)
|
||||
*
|
||||
* \param[in] G Graph
|
||||
* \param[out] marked Bereits besuchte Knoten
|
||||
* \param[out] edgeTo Vektor mit dem Nachfolgeknoten zu jedem Knoten
|
||||
* \param[in] v Startknoten
|
||||
* \return true Graph ist zusammenhaengend
|
||||
* false Graph ist nicht zusammenhaengend
|
||||
*/
|
||||
|
||||
bool DFS(const EdgeWeightedGraph &G, int v, std::vector<bool> &marked, std::vector<int> &edgeTo) {
|
||||
bool ret = true;
|
||||
marked.clear();
|
||||
marked.resize(G.getV(), false);
|
||||
|
||||
edgeTo.clear();
|
||||
edgeTo.resize(G.getV(), -1);
|
||||
|
||||
DFS_recursive(G, v, marked, edgeTo);
|
||||
std::cout << std::endl;
|
||||
for (bool value: marked)
|
||||
ret = ret && value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fuehrt eine iterative Breitensuche im Graphen g, ab dem Knoten v aus.
|
||||
* Alle besuchten Knoten werden ausgegeben.
|
||||
*
|
||||
* \param[in] G Graph
|
||||
* \param[in] v Startknoten
|
||||
* \param[out] marked Gibt an welche Knoten besucht wurden bei der Suche
|
||||
* \param[out] edgeTo Gibt den Nachfolgerknoten eines Knoten an
|
||||
* \return true Graph ist zusammenhaengend
|
||||
* false Graph ist nicht zusammenhaengend
|
||||
*/
|
||||
bool BFS(const EdgeWeightedGraph &G, int v, std::vector<bool> &marked, std::vector<int> &edgeTo) {
|
||||
marked.clear();
|
||||
marked.resize(G.getV(), false);
|
||||
edgeTo.clear();
|
||||
edgeTo.resize(G.getV(), -1);
|
||||
std::queue<int> q;
|
||||
|
||||
marked[v] = true;
|
||||
q.push(v);
|
||||
|
||||
while (!q.empty()) {
|
||||
int currentV = q.front();
|
||||
q.pop();
|
||||
std::cout << currentV << " "; // Knoten besuchen (hier: ausgeben)
|
||||
|
||||
for (const Edge &edge: G.getAdj(currentV)) {
|
||||
int w = edge.other(currentV);
|
||||
if (!marked[w]) {
|
||||
edgeTo[w] = currentV;
|
||||
marked[w] = true;
|
||||
q.push(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <20>berpr<70>fen, ob alle Knoten besucht wurden
|
||||
for (bool m: marked) {
|
||||
if (!m) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
59
P4/KruskalMST.cpp
Executable file
59
P4/KruskalMST.cpp
Executable file
@@ -0,0 +1,59 @@
|
||||
#include "KruskalMST.h"
|
||||
|
||||
/**
|
||||
* Erstellt einen MST zum Graph G mit dem Kruskal Algorithmus
|
||||
*
|
||||
* \param[in] G Kantengewichteter-Graph
|
||||
*/
|
||||
KruskalMST::KruskalMST(EdgeWeightedGraph G) {
|
||||
treeID.resize(G.getV());
|
||||
std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge> > pq;
|
||||
std::vector<Edge> e = G.edges(); // liefert alle Kanten von G
|
||||
|
||||
for (int i = 0; i < e.size(); i++)
|
||||
pq.push(e[i]);
|
||||
|
||||
// zu Beginn ist jeder Knoten ein eigener Baum
|
||||
for (int i = 0; i < G.getV(); i++)
|
||||
treeID[i] = i;
|
||||
|
||||
while (!pq.empty()) {
|
||||
Edge e = pq.top();
|
||||
pq.pop();
|
||||
int v = e.either();
|
||||
int w = e.other(v);
|
||||
// Wenn Knoten v und w zu unterschiedlichen B?umen geh?rt,
|
||||
// k<>nnen diese mit der Kante e ohne Zykel verbunden werden
|
||||
if (treeID[v] != treeID[w]) {
|
||||
mst.push_back(e);
|
||||
int treeID_w = treeID[w];
|
||||
for (int i = 0; i < G.getV(); i++) {
|
||||
// BaumID von v und w
|
||||
if (treeID[i] == treeID_w) // angleichen
|
||||
treeID[i] = treeID[v];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle Kanten vom MST zurueck
|
||||
*
|
||||
* \return Vektor mit Kanten des MST
|
||||
*/
|
||||
std::vector<Edge> KruskalMST::edges() const {
|
||||
return mst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Summe aller Gewichte im MST zurueck
|
||||
*
|
||||
* \return Summe der Gewichte im MST
|
||||
*/
|
||||
double KruskalMST::weight() const {
|
||||
double gew = 0.0;
|
||||
for (Edge e: this->mst)
|
||||
gew += e.weight();
|
||||
|
||||
return gew;
|
||||
}
|
||||
18
P4/KruskalMST.h
Executable file
18
P4/KruskalMST.h
Executable file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include "EdgeWeightedGraph.h"
|
||||
|
||||
class KruskalMST {
|
||||
private:
|
||||
std::vector<Edge> mst; // MST-Kanten
|
||||
std::vector<int> treeID; // BaumId zu jedem Knoten
|
||||
public:
|
||||
KruskalMST() {
|
||||
};
|
||||
|
||||
KruskalMST(EdgeWeightedGraph G);
|
||||
|
||||
std::vector<Edge> edges() const; // liefert MST
|
||||
double weight() const; // berechnet Gesamtkosten des MST
|
||||
};
|
||||
70
P4/PrimMST.cpp
Executable file
70
P4/PrimMST.cpp
Executable file
@@ -0,0 +1,70 @@
|
||||
#include "PrimMST.h"
|
||||
|
||||
/**
|
||||
* Erstellt einen MST zum Graph G mit dem Prim Algorithmus
|
||||
*
|
||||
* \param[in] G Kantengewichteter-Graph
|
||||
* \param[in] s Startknoten
|
||||
*/
|
||||
PrimMST::PrimMST(EdgeWeightedGraph G, int s) {
|
||||
marked.resize(G.getV(), false);
|
||||
// lege alle Kanten vom Startknoten 0 ausgehend in die Priority Queue (PQ)
|
||||
// setzt voraus, dass G zusammenhaengend ist
|
||||
visit(G, s);
|
||||
while (!pq.empty()) {
|
||||
Edge e = pq.top(); // Hole Kante mit geringstem Gewicht aus PQ
|
||||
pq.pop(); // entferne diese Kante aus PQ
|
||||
int v = e.either(); // Knoten 1 der Kante
|
||||
int w = e.other(v); // Knoten 2 der Kante
|
||||
|
||||
// <20>berspringen, falls beide Knoten im Baum markiert sind
|
||||
if (marked[v] && marked[w])
|
||||
continue; // Zykel-Detektion
|
||||
|
||||
mst.push_back(e); // F<>ge Kante e zum MST hinzu
|
||||
if (!marked[v])
|
||||
visit(G, v); // Knoten v oder w zum MSP
|
||||
if (!marked[w])
|
||||
visit(G, w); // hinzuf?gen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Markiert Knoten v im Graph G als markiert und fuegt alle Nachbarn zur pq hinzu
|
||||
*
|
||||
* \param[in] G Kantengewichteter-Graph
|
||||
* \param[in] v Knoten im Graph G
|
||||
*/
|
||||
void PrimMST::visit(EdgeWeightedGraph G, int v) {
|
||||
marked[v] = true;
|
||||
std::vector<Edge> Tedges = G[v]; // liefert alle Kanten ausgehend vom Knoten v
|
||||
|
||||
// Lege alle Kanten von v zu unmarkierten
|
||||
// (noch nicht besuchten) Knoten in die PQ ab
|
||||
for (int i = 0; i < Tedges.size(); i++) {
|
||||
if (!marked[Tedges[i].other(v)])
|
||||
pq.push(Tedges[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle Kanten vom MST zurueck
|
||||
*
|
||||
* \return Vektor mit Kanten des MST
|
||||
*/
|
||||
std::vector<Edge> PrimMST::edges() const {
|
||||
return mst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Summe aller Gewichte im MST zurueck
|
||||
*
|
||||
* \return Summe der Gewichte im MST
|
||||
*/
|
||||
double PrimMST::weight() const {
|
||||
double gew = 0.0;
|
||||
for (Edge e: this->mst) {
|
||||
gew += e.weight();
|
||||
}
|
||||
return gew;
|
||||
}
|
||||
28
P4/PrimMST.h
Executable file
28
P4/PrimMST.h
Executable file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#include "EdgeWeightedGraph.h"
|
||||
|
||||
class PrimMST {
|
||||
private:
|
||||
std::vector<bool> marked; // MST-Knoten
|
||||
std::vector<Edge> mst; // MST-Kanten
|
||||
/*
|
||||
* PriorityQueue die alle Kanten speichert und mit pq.top()
|
||||
* die Kante mit dem kleinsten Gewicht zurueck gibt.
|
||||
*/
|
||||
std::priority_queue<Edge, std::vector<Edge>, std::greater<Edge> > pq;
|
||||
|
||||
public:
|
||||
PrimMST() {
|
||||
}
|
||||
|
||||
PrimMST(EdgeWeightedGraph G, int s);
|
||||
|
||||
void visit(EdgeWeightedGraph G, int v);
|
||||
|
||||
std::vector<Edge> edges() const;
|
||||
|
||||
double weight() const;
|
||||
};
|
||||
152
P4/PriorityQueue.h
Executable file
152
P4/PriorityQueue.h
Executable file
@@ -0,0 +1,152 @@
|
||||
#pragma once
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
|
||||
namespace Utils {
|
||||
/**
|
||||
* Wrapper-Klasse um Vergleiche unabhaengig von value zu ermoeglichen
|
||||
*
|
||||
* \tparam[in] _CompareValueTyupe Typ der compareValue
|
||||
* \tparam[in] _ValueType Typ der value
|
||||
*/
|
||||
template<class _CompareValueTyupe, class _ValueType>
|
||||
class CompareContainer {
|
||||
public:
|
||||
_CompareValueTyupe compareValue;
|
||||
_ValueType value;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* \param[in] compareValue Anhand dieser Variable wird verglichen
|
||||
* \param[in] value Variable fuer die ein Vergleich benoetigt wird
|
||||
*/
|
||||
CompareContainer(_CompareValueTyupe compareValue, _ValueType value) : compareValue{compareValue}, value{value} {
|
||||
}
|
||||
|
||||
/**
|
||||
* Vergleicht zwei CompareContainer
|
||||
*
|
||||
* \param[in] other Container 2
|
||||
* \return true, wenn die compareValue von this und other gleich ist. Ansonsten false
|
||||
*/
|
||||
bool operator==(const CompareContainer &other) const { return compareValue == other.compareValue; }
|
||||
|
||||
/**
|
||||
* Vergleicht zwei CompareContainer
|
||||
*
|
||||
* \param[in] other Container 2
|
||||
* \return true, wenn die compareValue von this und other ungleich ist. Ansonsten false
|
||||
*/
|
||||
bool operator!=(const CompareContainer &other) const { return !this->operator==(other); }
|
||||
|
||||
/**
|
||||
* Vergleicht zwei CompareContainer
|
||||
*
|
||||
* \param[in] other Container 2
|
||||
* \return true, wenn die compareValue von this kleiner als die von other ist. Ansonsten false
|
||||
*/
|
||||
bool operator<(const CompareContainer &other) const { return compareValue < other.compareValue; }
|
||||
|
||||
/**
|
||||
* Vergleicht zwei CompareContainer
|
||||
*
|
||||
* \param[in] other Container 2
|
||||
* \return true, wenn die compareValue von this groesser als die von other ist. Ansonsten false
|
||||
*/
|
||||
bool operator>(const CompareContainer &other) const {
|
||||
return !this->operator<(other) && !this->operator==(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vergleicht zwei CompareContainer
|
||||
*
|
||||
* \param[in] other Container 2
|
||||
* \return true, wenn die compareValue von this kleiner oder gleich, wie die von other ist. Ansonsten false
|
||||
*/
|
||||
bool operator<=(const CompareContainer &other) const { return !this->operator>(other); }
|
||||
|
||||
/**
|
||||
* Vergleicht zwei CompareContainer
|
||||
*
|
||||
* \param[in] other Container 2
|
||||
* \return true, wenn die compareValue von this groesser oder gleich, wie die von other ist. Ansonsten false
|
||||
*/
|
||||
bool operator>=(const CompareContainer &other) const { return !this->operator<(other); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper-Klasse um die Funktionsweise der std::priority_queue zu erweitern. Ermoeglicht es Objekte mit einem unabhaengigen Gewicht in die pq zu laden und erweitert die pq mit weiteren Methoden.
|
||||
* Das kleinste Gewicht ist immer an Position top()
|
||||
*
|
||||
* \tparam[in] _Tr Datentyp der PriorityQueue
|
||||
*/
|
||||
template<typename _Tr>
|
||||
class PriorityQueue : public std::priority_queue<CompareContainer<double, _Tr>, std::vector<CompareContainer<double,
|
||||
_Tr> >, std::greater<CompareContainer<double, _Tr> > > {
|
||||
public:
|
||||
/**
|
||||
* Fuegt ein item mit dem Gewicht weight zur pq hinzu.
|
||||
*
|
||||
* \param[in] item Objekt was zur pq hinzugefuegt werden soll
|
||||
* \param[in] weight Das Gewicht mit dem item priorisiert werden soll
|
||||
*/
|
||||
void push(_Tr item, double weight) {
|
||||
std::priority_queue<CompareContainer<double, _Tr>, std::vector<CompareContainer<double, _Tr> >, std::greater
|
||||
<CompareContainer<double, _Tr> > >::push(CompareContainer<double, _Tr>(weight, item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt das Item an Position top() zurueck und entfernt dieses aus der pq.
|
||||
*
|
||||
* \return Item an Position top()
|
||||
*/
|
||||
_Tr pop_top() {
|
||||
_Tr item = this->top().value;
|
||||
this->pop();
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entfernt element aus der pq und gibt zurueck, ob es gefunden und entfernt wurde.
|
||||
*
|
||||
* \return true, wenn element aus der pq entfernt wurde, sonst false
|
||||
*/
|
||||
bool remove(const _Tr &element) {
|
||||
for (auto it = this->c.begin(); it != this->c.end(); it++) {
|
||||
if ((*it).value == element) {
|
||||
this->c.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht nach element in der pq und gibt zurueck ob es gefunden wurde
|
||||
*
|
||||
* \return true, wenn element in der pq gefunden wurde, sonst false
|
||||
*/
|
||||
bool contains(const _Tr &element) {
|
||||
for (auto it = this->c.begin(); it != this->c.end(); it++) {
|
||||
if ((*it).value == element) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tauscht das Gewicht von element aus und gibt zurueck ob es gefunden wurde.
|
||||
*
|
||||
* \return true, wenn element in der pq gefunden wurde, sonst false
|
||||
*/
|
||||
bool change(const _Tr &element, double weight) {
|
||||
if (!remove(element)) return false;
|
||||
this->push(element, weight);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
18182
P4/catch.h
Executable file
18182
P4/catch.h
Executable file
File diff suppressed because it is too large
Load Diff
18182
P4/catch.hpp
Executable file
18182
P4/catch.hpp
Executable file
File diff suppressed because it is too large
Load Diff
13
P4/graph1.txt
Executable file
13
P4/graph1.txt
Executable file
@@ -0,0 +1,13 @@
|
||||
7
|
||||
11
|
||||
0 1 7
|
||||
0 3 5
|
||||
1 2 8
|
||||
1 3 9
|
||||
1 4 7
|
||||
2 4 5
|
||||
3 4 15
|
||||
3 5 6
|
||||
4 5 8
|
||||
4 6 9
|
||||
5 6 11
|
||||
62
P4/graph2.txt
Executable file
62
P4/graph2.txt
Executable file
@@ -0,0 +1,62 @@
|
||||
20
|
||||
60
|
||||
0 1 6
|
||||
0 4 47
|
||||
0 8 11
|
||||
0 16 19
|
||||
0 19 1
|
||||
1 3 4
|
||||
1 7 9
|
||||
1 10 21
|
||||
1 13 33
|
||||
1 16 42
|
||||
2 3 5
|
||||
2 5 15
|
||||
2 12 24
|
||||
2 13 37
|
||||
2 17 39
|
||||
3 4 46
|
||||
3 11 16
|
||||
3 18 32
|
||||
4 5 36
|
||||
4 7 39
|
||||
4 11 40
|
||||
4 15 49
|
||||
4 18 4
|
||||
5 6 8
|
||||
5 11 16
|
||||
5 12 19
|
||||
5 16 21
|
||||
5 18 30
|
||||
6 7 7
|
||||
6 9 32
|
||||
6 13 33
|
||||
6 16 36
|
||||
6 17 42
|
||||
7 8 49
|
||||
7 11 6
|
||||
7 15 11
|
||||
7 16 26
|
||||
7 17 32
|
||||
8 9 38
|
||||
8 12 47
|
||||
8 14 3
|
||||
8 18 6
|
||||
9 10 21
|
||||
9 14 27
|
||||
9 19 38
|
||||
10 13 40
|
||||
10 15 3
|
||||
10 19 15
|
||||
11 14 17
|
||||
11 17 30
|
||||
11 19 38
|
||||
12 15 39
|
||||
12 17 6
|
||||
13 18 9
|
||||
14 15 17
|
||||
13 19 25
|
||||
15 16 31
|
||||
15 19 42
|
||||
16 18 11
|
||||
17 19 24
|
||||
45
P4/graph3.txt
Executable file
45
P4/graph3.txt
Executable file
@@ -0,0 +1,45 @@
|
||||
20
|
||||
43
|
||||
0 4 47
|
||||
0 18 12
|
||||
1 3 4
|
||||
1 7 9
|
||||
1 10 21
|
||||
1 13 33
|
||||
1 16 42
|
||||
2 3 5
|
||||
2 12 24
|
||||
2 13 37
|
||||
2 17 39
|
||||
3 5 27
|
||||
3 8 17
|
||||
3 11 16
|
||||
3 12 5
|
||||
4 18 4
|
||||
5 6 8
|
||||
5 11 16
|
||||
5 12 19
|
||||
5 16 21
|
||||
6 7 7
|
||||
6 13 33
|
||||
6 16 36
|
||||
6 17 42
|
||||
7 8 49
|
||||
7 11 6
|
||||
7 16 26
|
||||
7 17 32
|
||||
8 12 47
|
||||
8 14 3
|
||||
8 16 46
|
||||
9 10 21
|
||||
9 19 38
|
||||
10 15 3
|
||||
10 19 15
|
||||
11 14 17
|
||||
11 13 32
|
||||
11 17 30
|
||||
12 14 26
|
||||
12 17 6
|
||||
13 16 35
|
||||
14 17 2
|
||||
15 19 42
|
||||
296
P4/main.cpp
Executable file
296
P4/main.cpp
Executable file
@@ -0,0 +1,296 @@
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include "catch.h"
|
||||
#include <iostream>
|
||||
#include "EdgeWeightedGraph.h"
|
||||
#include "PrimMST.h"
|
||||
#include "Graphsearch.h"
|
||||
#include "KruskalMST.h"
|
||||
#include "DijkstraSP.h"
|
||||
using namespace std;
|
||||
|
||||
bool isInGrapf(EdgeWeightedGraph gr, int v) {
|
||||
if (v > gr.getV())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrintGrapf(EdgeWeightedGraph g) {
|
||||
vector<vector<Edge> > adj = g.getAdj();
|
||||
|
||||
cout << endl;
|
||||
for (int i = 0; i < g.getV(); i++) {
|
||||
cout << i << " -> ";
|
||||
for (int j = 0; j < adj[i].size(); j++) {
|
||||
cout << adj[i][j].other(i) << "[" << adj[i][j].weight() << "]";
|
||||
if (j < adj[i].size() - 1) {
|
||||
cout << " -> ";
|
||||
}
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void print_digraph(EdgeWeightedDigraph graph) {
|
||||
int prev = -1;
|
||||
for (DirectedEdge e: graph.edges()) {
|
||||
if (e.from() != prev)
|
||||
cout << endl << e.from();
|
||||
|
||||
cout << " -> " << e.to() << " [" << e.weight() << "] ";
|
||||
prev = e.from();
|
||||
}
|
||||
|
||||
cout << endl << endl;
|
||||
}
|
||||
|
||||
void print_mst(vector<Edge> mst) {
|
||||
vector<int> v;
|
||||
cout << endl;
|
||||
for (Edge e: mst) {
|
||||
int vorhanden = 0;
|
||||
for (int i: v) {
|
||||
if (e.either() == i)
|
||||
vorhanden++;
|
||||
}
|
||||
if (vorhanden == 0) {
|
||||
cout << e.either();
|
||||
for (Edge z: mst) {
|
||||
if (z.either() == e.either()) {
|
||||
cout << " -> " << z.other(z.either()) << " [" << z.weight() << "] ";
|
||||
}
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
v.push_back(e.either());
|
||||
}
|
||||
}
|
||||
|
||||
void search(EdgeWeightedGraph gra, int type) {
|
||||
int search;
|
||||
cout << endl << "Suche nach ?> ";
|
||||
cin >> search;
|
||||
vector<bool> marked;
|
||||
vector<int> edgeTo;
|
||||
bool zsm;
|
||||
|
||||
if (!isInGrapf(gra, search))
|
||||
cout << search << " ist nicht im Graphen" << endl;
|
||||
|
||||
if (type == 2) {
|
||||
cout << "Tiefensuche(Depth - First - Search(DFS)) - Startknoten: " << search << endl << "Besuchsreihenfolge :"
|
||||
<< endl;
|
||||
zsm = Graphsearch::DFS(gra, search, marked, edgeTo);
|
||||
} else {
|
||||
cout << "Breitensuche(Breadth - First - Search(BFS)) - Startknoten: " << search << endl <<
|
||||
"Besuchsreihenfolge :"
|
||||
<< endl;
|
||||
zsm = Graphsearch::BFS(gra, search, marked, edgeTo);
|
||||
}
|
||||
|
||||
cout << endl << "Marked Array:";
|
||||
for (int i = 0; i < marked.size(); i++)
|
||||
cout << endl << i << " -> " << marked[i];
|
||||
|
||||
cout << endl << "Edge To Array:";
|
||||
for (int i = 0; i < edgeTo.size(); i++)
|
||||
cout << endl << i << " -> " << edgeTo[i];
|
||||
|
||||
if (zsm)
|
||||
cout << endl << "Graph ist zusammenhaengend" << endl;
|
||||
else
|
||||
cout << endl << "Graph ist nicht zusammenhaengend" << endl;
|
||||
}
|
||||
|
||||
bool get_edge_values(EdgeWeightedGraph &gra, int &from, int &to) {
|
||||
cout << endl << "Start Knoten ?>";
|
||||
cin >> from;
|
||||
|
||||
if (!isInGrapf(gra, from)) {
|
||||
cout << from << " ist nicht im Graphen" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
cout << endl << "Ziel Knoten ?>";
|
||||
cin >> to;
|
||||
|
||||
if (!isInGrapf(gra, to)) {
|
||||
cout << to << " ist nicht im Graphen" << endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Starte Unit-Tests
|
||||
Catch::Session().run();
|
||||
int selection;
|
||||
string graph;
|
||||
EdgeWeightedGraph gra(graph);
|
||||
EdgeWeightedDigraph wgra(graph);
|
||||
|
||||
while (true) {
|
||||
if (graph == "")
|
||||
cout << endl << "Graph nicht gefunden" << endl;
|
||||
|
||||
cout << endl
|
||||
<< "Praktikum 4: Graphenalgorithem:" << endl
|
||||
<< "1) Graph einlesen" << endl
|
||||
<< "2) Tiefensuche" << endl
|
||||
<< "3) Breitensuche" << endl
|
||||
<< "4) MST nach Prim" << endl
|
||||
<< "5) MST nach Kruskal" << endl
|
||||
<< "6) Kuerzeste Wege nach Dijkstra" << endl
|
||||
<< "7) Ausgabe der Adjazenzliste" << endl
|
||||
<< "8) Kante löschen" << endl
|
||||
<< "9) Kante hinzufügen" << endl
|
||||
<< "10) Programm beenden" << endl
|
||||
<< "? > ";
|
||||
cin >> selection;
|
||||
|
||||
switch (selection) {
|
||||
case 1: {
|
||||
int auswahl;
|
||||
cout << endl << "Graph einlesen" << endl
|
||||
<< "1) Graph1" << endl
|
||||
<< "2) Graph2" << endl
|
||||
<< "3) Graph3" << endl
|
||||
<< "?> ";
|
||||
cin >> auswahl;
|
||||
|
||||
switch (auswahl) {
|
||||
case 1:
|
||||
graph = "graph1.txt";
|
||||
break;
|
||||
case 2:
|
||||
graph = "graph2.txt";
|
||||
break;
|
||||
case 3:
|
||||
graph = "graph3.txt";
|
||||
break;
|
||||
}
|
||||
if (graph != "") {
|
||||
gra = EdgeWeightedGraph(graph);
|
||||
wgra = EdgeWeightedDigraph(graph);
|
||||
cout << endl << "Graph " << auswahl << " wurde eingelesen" << endl;
|
||||
} else
|
||||
cout << endl << "Graph nicht gefunden" << endl;
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
search(gra, selection);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
search(gra, selection);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int start = 0;
|
||||
cout << endl << "Start Knoten ?> ";
|
||||
cin >> start;
|
||||
|
||||
|
||||
if (!isInGrapf(gra, start)) {
|
||||
cout << start << " ist nicht im Graphen" << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
PrimMST test(gra, start);
|
||||
cout << "Minimaler Spannbaum(MST) nach Prim :" << endl;
|
||||
cout << "Gewicht: " << test.weight();
|
||||
vector<Edge> mst = test.edges();
|
||||
|
||||
print_mst(mst);
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
KruskalMST test(gra);
|
||||
|
||||
cout << "Minimaler Spannbaum(MST) nach Kruskal :" << endl;
|
||||
cout << "Gewicht: " << test.weight();
|
||||
vector<Edge> mst = test.edges();
|
||||
|
||||
print_mst(mst);
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
int start, ziel = 0;
|
||||
|
||||
cout << endl << "Start Knoten ?> ";
|
||||
cin >> start;
|
||||
|
||||
if (!isInGrapf(gra, start)) {
|
||||
cout << start << " ist nicht im Graphen" << endl;
|
||||
continue;
|
||||
}
|
||||
cout << endl << "Ziel Knoten ?>";
|
||||
cin >> ziel;
|
||||
|
||||
if (!isInGrapf(gra, ziel)) {
|
||||
cout << ziel << " ist nicht im Graphen" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
DijkstraSP dijkstra(wgra, start);
|
||||
vector<DirectedEdge> path = dijkstra.pathTo(ziel);
|
||||
print_digraph(wgra);
|
||||
double kosten = 0.0;
|
||||
string out = "";
|
||||
cout << "Pfad: ";
|
||||
for (DirectedEdge de: path) {
|
||||
kosten += de.weight();
|
||||
out += to_string(de.from()) + " [" + to_string(de.weight()) + "] " + " -> ";
|
||||
}
|
||||
|
||||
if (kosten == 0.0) {
|
||||
cout << "Kein Weg gefunden" << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
cout << out;
|
||||
cout << path[path.size() - 1].to() << endl;
|
||||
cout << "Kosten: " << kosten << endl;
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
PrintGrapf(gra);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
int from, to;
|
||||
if (get_edge_values(gra, from, to)) {
|
||||
Edge n(from, to, 0);
|
||||
DirectedEdge m(from, to, 0);
|
||||
gra.del_Edge(n);
|
||||
wgra.del_Edge(m);
|
||||
cout << "Die Kante (" << from << " ; " << to << ") wurde gelöscht." << endl;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 9: {
|
||||
int from, to, weight;
|
||||
bool a = get_edge_values(gra, from, to);
|
||||
|
||||
cout << endl << "Gewicht ?>";
|
||||
cin >> weight;
|
||||
|
||||
if (a) {
|
||||
Edge n(from, to, weight);
|
||||
DirectedEdge m(from, to, weight);
|
||||
gra.add(n);
|
||||
wgra.add(m);
|
||||
|
||||
cout << "Die Kante (" << from << " ; " << to << " ; " << weight << ") wurde hinzugefügt." << endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 10: {
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user