-
Notifications
You must be signed in to change notification settings - Fork 4
/
Graph.h
225 lines (168 loc) · 6.37 KB
/
Graph.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#ifndef GRAPH_H
#define GRAPH_H
#include <list>
#include <string>
#include <deque>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#include <memory>
#include "Node.h"
#include "Edge.h"
/* --------------------------------------------------------------------------------------------- */
class Graph
{
private:
//! @Datataypes
// This is a helper function object in order to sort the nodes by id in a set of nodes.
struct SortNodeByIdHelper {
bool operator()(const Node* l, const Node* r) const {
return l->getId() < r->getId();
}
};
// some typedefs for containers that are used in this class
typedef std::set<Node*, SortNodeByIdHelper> tNodePtrSet;
typedef std::list<Edge*> tEdgePtrList;
typedef std::deque<Edge*> tPath;
typedef std::vector<Edge*> tEdges;
typedef std::vector<Node*> tNodes;
struct tDijkstraInfo
{
double distance;
Node* prevNode;
Edge* prevEdge;
};
typedef std::map<Node*, tDijkstraInfo> tDijkstraMap;
public:
class Exception;
class NodeCreationException;
class InvalidNodeException;
class NotFoundException;
public:
virtual ~Graph();
/**
*/
template<class T>
T& makeNode(T&& node);
template<class T, class... Args>
T& makeNode(Args&&... args) { return makeNode(T(std::forward<Args>(args)...)); }
template<class T>
T& makeEdge(T&& edge);
template<class T, class... Args>
T& makeEdge(Args&&... args) { return makeEdge(T(std::forward<Args>(args)...)); }
/** Constructs to Edges. */
template<class T, class... Args>
void makeBiEdge(Node& n1, Node& n2, Args&&... args) {
makeEdge(T(n1, n2, std::forward<Args>(args)...));
makeEdge(T(n2, n1, std::forward<Args>(args)...));
}
template<class T>
Graph& operator << (T&& rEdge) {
// forward as r-value reference
makeEdge(std::move(rEdge))
return *this;
}
tNodePtrSet& getNodes() { return m_nodes; }
/**
* Deletes the given Edge from the graph.
* The Edge object will be destroyed after this function call.
* @return true if the Edge was found and deleted, false otherwise.
*/
bool remove(const Edge& rEdge);
/**
* Deletes the given Node from the graph.
* The Node object will be destroyed after this function call.
* All connected edges will be destroyed, too.
* @return true if the Node was found and deleted, false otherwise.
*/
bool remove(const Node& rNode);
/**
* Retrieves a node by the given id.
* @return a pointer to the node or NULL if not found.
*/
Node* Graph::findNodeById(const std::string& id);
/** Retrieves all edges that have rSrc as source node and rDst as destination node. */
tEdges findEdges(const Node& rSrc, const Node& rDst);
/** Retrieves all edges whose id for the source node is rSrc and rDst for the dest node. */
tEdges findEdges(const std::string& srcId, const std::string& dstId);
/** Generates a list of all connected nodes. Each line represents an edge. */
std::string toString() const;
/**
* Saves the graph as dot file. The tool Graphiz can generate an image from this file.
* @param rFimename the target file name.
*/
void saveAsDot(const std::string& rFilename) const;
/**
* The Dijkstra algorithm calculates the shortest path of all nodes to a single root node.
* @param rSrcNode is the node to calculate the distance to.
* @param pDstNode the algorithm stops, if the path to *pDstNode is found.
* @param pFoundDst contains the address of the destination node or is set to NULL, if no path was found.
* @return a map of nodes with associated routing information to the source node..
*/
tDijkstraMap findDistancesDijkstra(const Node& rSrcNode, const Node* pDstNode, Node** pFoundDst);
/**
* Calculate the shortest path from a source node to a destination node.
* @param the source node.
* @param the destination node.
* @return tPath is a deque of edges and represents the route from rSrc to rDst.
*/
tPath findShortestPathDijkstra(const Node& rSrc, const Node& rDst);
protected:
tNodePtrSet m_nodes;
tEdgePtrList m_edges;
#ifdef TESTING
friend class GraphTesting;
#endif
};
/* --------------------------------------------------------------------------------------------- */
class Graph::Exception
{
public:
Exception(const std::string& what) : m_what(what) { }
virtual ~Exception() {}
const std::string& what() const { return m_what; }
private:
std::string m_what;
};
class Graph::NodeCreationException : public Graph::Exception {
public: NodeCreationException(const std::string& what) : Exception(what) { }
};
class Graph::InvalidNodeException : public Graph::Exception {
public: InvalidNodeException(const std::string& what) : Exception(what) { }
};
class Graph::NotFoundException : public Graph::Exception {
public: NotFoundException(const std::string& what) : Exception(what) { }
};
/* --------------------------------------------------------------------------------------------- */
template<class T>
T& Graph::makeNode(T&& node)
{
// is there already a node with the given id?
auto it = m_nodes.lower_bound(&node);
if (it != m_nodes.end() && (*it)->getId() == node.getId()) {
throw NodeCreationException("NodeID is not unique: " + node.getId());
}
// if not, create a new node
auto ret = m_nodes.insert(it, new T(std::move(node)));
// ret.first is an iterator to the new element.
// We must dereference it twice (iterator & unique_ptr) in order to get the node reference.
return **ret;
}
/* --------------------------------------------------------------------------------------------- */
template<class T>
T& Graph::makeEdge(T&& edge)
{
// check if src and destination nodes are in the graph
if (std::find(m_nodes.begin(), m_nodes.end(), &edge.getDstNode()) == m_nodes.end()) {
throw InvalidNodeException("source node is not in the graph");
}
if (std::find(m_nodes.begin(), m_nodes.end(), &edge.getSrcNode()) == m_nodes.end()) {
throw InvalidNodeException("destination node is not in the graph");
}
T* newEdge = new T(std::move(edge));
m_edges.push_back(newEdge);
return *newEdge;
}
/* --------------------------------------------------------------------------------------------- */
#endif