#ifndef GRAPH_H #define GRAPH_H #include #include // directed, weighted template class Graph { private: struct Edge { Edge(const T& destination, float weight = 0); Edge(const Edge& other); Edge& operator=(const Edge& other); const T* m_destination; float m_weight; }; struct Vertex { Vertex(const T& data); Vertex(const Vertex& other); Vertex& operator=(const Vertex& other); void addEdge(const T& destination, float weight = 0); void removeEdge(const T& destination, float weight = 0); void removeAllEdgesTo(const T& destination); const T* m_data; std::vector m_edges; }; public: Graph(); // Capacity bool empty() const; size_t numberOfVertices() const; size_t numberOfEdges() const; // Modifiers bool addVertex(const T& data); bool removeVertex(const T& data); bool addEdge(const T& source, const T& destination, float weight = 0); bool removeEdge(const T& source, const T& destination, float weight = 0); bool removeAllEdges(const T& source, const T& destination); // Lookup bool contains(const T& data) const; std::vector vertices() const; std::vector neighboursOf(const T& data) const; std::vector edgesBetween(const T& source, const T& destination) const; std::string serialize() const; private: typename std::vector::const_iterator find(const T& data) const; typename std::vector::iterator find(const T& data); std::vector m_vertices; }; // non-member functions // template typename std::vector subtee_breathFirst(const Graph& graph, const T& root); // template bool connected(const Graph& graph); // template bool circular(const Graph& graph); // template typename std::vector path(const Graph& graph, const T& a, const T& b); // definitions // Edge template Graph::Edge::Edge(const T& destination, float weight) : m_destination(&destination) , m_weight(weight) { } template Graph::Edge::Edge(const Edge& other) : m_destination(other.m_destination) , m_weight(other.m_weight) { } template typename Graph::Edge& Graph::Edge::operator=(const Edge& other) { if (this != &other) { m_destination = other.m_destination; m_weight = other.m_weight; } return *this; } // Vertex template Graph::Vertex::Vertex(const T& data) : m_data(&data) , m_edges() { } template Graph::Vertex::Vertex(const Vertex& other) : m_data(other.m_data) , m_edges(other.m_edges) { } template typename Graph::Vertex& Graph::Vertex::operator=(const Vertex& other) { if (this != &other) { m_data = other.m_data; m_edges.clear(); m_edges = other.m_edges; } return *this; } template void Graph::Vertex::addEdge(const T& destination, float weight) { Edge e(destination, weight); m_edges.push_back(e); } template void Graph::Vertex::removeEdge(const T& destination, float weight) { m_edges.erase(std::find_if(m_edges.begin(), m_edges.end(), [&destination, &weight](const Edge& e) { return e.m_destination == destination && e.m_weight == weight;})); } template void Graph::Vertex::removeAllEdgesTo(const T& destination) { std::remove_if(m_edges.begin(), m_edges.end(), [&destination](const Edge& e) { return e.m_destination == destination; }); } // Graph template Graph::Graph() : m_vertices() { } template bool Graph::empty() const { return m_vertices.empty(); } template size_t Graph::numberOfVertices() const { return m_vertices.size(); } template size_t Graph::numberOfEdges() const { size_t retval = 0; std::accumulate(m_vertices.begin(), m_vertices.end(), retval, [](size_t sum, const Vertex& v) { return sum + v.m_edges.size(); }); return retval; } template bool Graph::addVertex(const T& data) { if (find(data) != m_vertices.end()) return false; Vertex v(data); m_vertices.push_back(v); return true; } template bool Graph::removeVertex(const T& data) { typename std::vector::iterator it = find(data); if (it == m_vertices.end()) return false; m_vertices.erase(it); return true; } template bool Graph::addEdge(const T& source, const T& destination, float weight) { typename std::vector::iterator source_it = find(source); if (source_it == m_vertices.end()) return false; typename std::vector::iterator destination_it = find(destination); if (destination_it == m_vertices.end()) return false; (*source_it).addEdge(destination, weight); return true; } template bool Graph::removeEdge(const T& source, const T& destination, float weight) { typename std::vector::iterator it = find(source); if (it == m_vertices.end()) return false; (*it).removeEdge(destination, weight); return true; } template bool Graph::removeAllEdges(const T& source, const T& destination) { typename std::vector::iterator it = find(source); if (it == m_vertices.end()) return false; (*it).removeAllEdgesEdge(destination); return true; } template bool Graph::contains(const T& data) const { return find(data) != m_vertices.end(); } template std::vector Graph::vertices() const { std::vector retval; std::for_each(m_vertices.begin(), m_vertices.end(), [&retval](const Vertex& v) { retval.push_back(v.m_data); }); return retval; } template std::vector Graph::neighboursOf(const T& data) const { typename std::vector retval; typename std::vector::const_iterator vertex_it = find(data); if (vertex_it == m_vertices.end()) return retval; std::for_each((*vertex_it).m_edges.begin(), (*vertex_it).m_edges.end(), [&retval](const Edge& e) { retval.push_back(e.m_weight); }); return retval; } template std::vector Graph::edgesBetween(const T& source, const T& destination) const { std::vector retval; typename std::vector::const_iterator vertex_it = find(source); if (vertex_it == m_vertices.end()) return retval; std::for_each((*vertex_it).m_edges.begin(), (*vertex_it).m_edges.end(), [&retval, &destination](const Edge& e) { if (e.m_destination == &destination) retval.push_back(e.m_weight); }); return retval; } template std::string Graph::serialize() const { /// @todo implement me return std::string(""); } template typename std::vector::Vertex >::const_iterator Graph::find(const T& data) const { return std::find_if(m_vertices.begin(), m_vertices.end(), [&data](const Vertex& v) { return v.m_data == &data; }); } template typename std::vector::Vertex >::iterator Graph::find(const T& data) { return std::find_if(m_vertices.begin(), m_vertices.end(), [&data](const Vertex& v) { return v.m_data == &data; }); } /* template typename std::vector subtee_breathFirst(const Graph& graph, const T& root) { std::vector retval; std::vector q; q.push_back(root); while (!q.empty()) { T node = q.front(); q.pop_front(); retval.push_back(node); const std::vector neighbours = graph.neighbours(node); typename std::vector::const_iterator it; for (it = neighbours.begin(); it != neighbours.end(); ++it) q.push_back(*it); } return retval; } template bool connected(const Graph& graph) { std::vector connected; const std::vector vertices = graph.vertices(); typename std::vector::const_iterator it; for (it = vertices.begin(); it != vertices.end(); ++it) { const std::vector neighbours = graph.neighbours(*it); typename std::vector::const_iterator it2; for (it2 = neighbours.begin(); it2 != neighbours.end(); ++it2) connected.push_back(*it2); } typename std::vector::const_iterator last = std::unique(connected.begin(), connected.end()); return graph.size == std::distance(connected.begin(), last); } template bool circular(const Graph& graph) { /// @todo implemente me return true; } template typename std::vector path(const Graph& graph, const T& a, const T& b) { // Dijkstra's algorithm for single-source shortest path /// @todo implemente me return 0; } */ #endif // GRAPH_H