#ifndef GRAPH_H #define GRAPH_H #include #include #include #include #include template class Graph { private: class Vertex; class EdgeTo; public: typedef size_t size_type; typedef V value_type; typedef V* pointer; typedef const V* const_pointer; typedef V& reference; typedef const V& const_reference; typedef std::ptrdiff_t difference_type; struct Edge { Edge() : m_source(0), m_destination(0), m_weight() {} Edge(pointer source, pointer destination, E weight); Edge(const Edge& o); Edge& operator=(Edge o) { swap(o); return *this; } void swap(Edge& o); pointer getSource() const { return m_source; } pointer getDestination() const { return m_destination; } E getWeight() const { return m_weight; } pointer m_source; pointer m_destination; E m_weight; }; typedef Edge* edge_pointer; typedef Edge& edge_reference; Graph(bool isdirected = true) : m_directed(isdirected), m_vertices() {} Graph(const Graph& o) : m_directed(o.m_directed), m_vertices(o.m_vertices) {} Graph& operator=(Graph o) { swap(o); return *this; } void swap(Graph& o) { std::swap (m_directed, o.m_directed); std::swap(m_vertices, o.m_vertices); } // Properties bool directed() const { return m_directed; } // Capacity bool empty() const { return m_vertices.empty(); } size_type numberOfVertices() const { return m_vertices.size(); } size_type numberOfEdges() const; // Modifiers bool addVertex(const_reference data); bool removeVertex(const_reference data); bool addEdge(const_reference source, const_reference destination, float weight = 0); bool removeEdge(const_reference source, const_reference destination, float weight = 0); bool removeAllEdges(const_reference source, const_reference destination); // Lookup bool contains(const_reference data) const { return find(data) != m_vertices.end(); } std::vector vertices() const; std::vector neighboursOf(const_reference data) const; /// @todo come up with a more clear name std::vector edgesBetween(const_reference source, const_reference destination) const; std::vector edges() const; // iterators class vertex_iterator : public std::iterator { friend class Graph; public: typedef vertex_iterator self_type; typedef vertex_iterator& reference_self_type; typedef const vertex_iterator& const_reference_self_type; vertex_iterator() : m_it() {} ~vertex_iterator() {} vertex_iterator(const_reference_self_type o) : m_it(o.m_it) {} reference_self_type operator=(self_type o) { swap(o); return *this; } void swap(reference_self_type o) { std::swap(m_it, o.m_it); } reference operator*() { return *((*m_it).m_data); } pointer operator->() { return (*m_it).m_data; } self_type &operator++() { ++m_it; return *this; } self_type operator++(int) { self_type tmp(*this); ++(*this); return tmp; } self_type operator+(difference_type n) { self_type tmp(*this); tmp.pos_ += n; return tmp; } self_type &operator+=(difference_type n) { m_it += n; return *this; } bool operator==(const_reference_self_type o) const { return m_it == o.m_it; } bool operator!=(const_reference_self_type o) const { return !(*this == o); } private: vertex_iterator(typename std::vector::iterator it) : m_it(it) {} vertex_iterator(typename std::vector::const_iterator it) : m_it(it) {} typename std::vector::const_iterator m_it; }; vertex_iterator vertex_begin() { return vertex_iterator(m_vertices.begin()); } const vertex_iterator vertex_begin() const { return vertex_iterator(m_vertices.begin()); } vertex_iterator vertex_end() { return vertex_iterator(m_vertices.end()); } const vertex_iterator vertex_end() const { return vertex_iterator(m_vertices.end()); } class edge_iterator : public std::iterator { friend class Graph; public: typedef edge_iterator self_type; typedef edge_iterator& reference_self_type; typedef const edge_iterator& const_reference_self_type; edge_iterator() : m_vertices(), m_vertex_it(), m_edge_it(), m_edge() {} ~edge_iterator() {} edge_iterator(const_reference_self_type o); reference_self_type operator=(self_type o) { swap(o); return *this; } void swap(reference_self_type other); edge_reference operator*() { resetEdge(); return m_edge; } edge_pointer operator->() { resetEdge(); return &m_edge; } self_type &operator++() { advance(1); return *this; } self_type operator++(int) { self_type tmp(*this); advance(1); return tmp; } self_type operator+(difference_type n) { self_type tmp(*this); tmp.pos_ += n; return tmp; } self_type &operator+=(difference_type n) { advance(n); return *this; } bool operator==(const_reference_self_type o) const; bool operator!=(const_reference_self_type o) const { return !(*this == o); } private: edge_iterator(std::vector vertices, bool begin = true); void resetEdge(); void advance(int n); std::vector m_vertices; typename std::vector::iterator m_vertex_it; typename std::list::iterator m_edge_it; Edge m_edge; }; edge_iterator edge_begin() { return edge_iterator(m_vertices); } const edge_iterator edge_begin() const { return edge_iterator(m_vertices); } edge_iterator edge_end() { return edge_iterator(m_vertices, false); } const edge_iterator edge_end() const { return edge_iterator(m_vertices, false); } private: struct EdgeTo { EdgeTo(const_reference destination, E weight = E()); EdgeTo(const EdgeTo& o) : m_destination(o.m_destination), m_weight(o.m_weight) {} EdgeTo& operator=(EdgeTo o) { swap(o); return *this; } void swap(EdgeTo& o); bool operator==(const EdgeTo& other) const; pointer m_destination; E m_weight; }; struct Vertex { Vertex(const_reference data) : m_data(const_cast(&data)) , m_edges() {} Vertex(const Vertex& o) : m_data(o.m_data), m_edges(o.m_edges) {} Vertex& operator=(Vertex o) { swap(o); return *this; } void swap(Vertex& o) { std::swap(m_data, o.m_data); std::swap (m_edges, o.m_edges); } bool operator==(const Vertex& other) const; void addEdge(const_reference destination, E weight = E()); void removeEdge(const_reference destination, E weight = E()); void removeAllEdgesTo(const_reference destination); std::vector edges() const; pointer m_data; std::list m_edges; }; typename std::vector::const_iterator find(const_reference data) const; typename std::vector::iterator find(const_reference data); bool m_directed; std::vector m_vertices; }; // Edge template inline Graph::Edge::Edge(pointer source, pointer destination, E weight) : m_source(source) , m_destination(destination) , m_weight(weight) {} template inline Graph::Edge::Edge(const Edge& o) : m_source(o.m_source) , m_destination(o.m_destination) , m_weight(o.m_weight) {} template inline void Graph::Edge::swap(Edge& o) { std::swap(m_source, o.m_source); std::swap(m_destination, o.m_destination); std::swap(m_weight, o.m_weight); } // edge iterator template inline Graph::edge_iterator::edge_iterator(const_reference_self_type o) : m_vertices(o.m_vertices) , m_vertex_it(o.m_vertex_it) , m_edge_it(o.m_edge_it) , m_edge() {} template bool Graph::edge_iterator::operator==(const_reference_self_type o) const { const bool this_is_at_end = m_vertex_it == m_vertices.end(); const bool other_is_at_end = o.m_vertex_it == o.m_vertices.end(); if ( this_is_at_end && other_is_at_end ) return true; if ( this_is_at_end != other_is_at_end ) return false; return *m_vertex_it == *(o.m_vertex_it) && *m_edge_it == *(o.m_edge_it); } template inline void Graph::edge_iterator::swap(reference_self_type other) { std::swap(m_vertices, other.m_vertices); std::swap(m_vertex_it, other.m_vertex_it); std::swap(m_edge_it, other.m_edge_it); std::swap(m_edge, other.m_edge); } template inline Graph::edge_iterator::edge_iterator(std::vector vertices, bool begin) : m_vertices(vertices), m_vertex_it(), m_edge_it(), m_edge() { if (begin) { m_vertex_it = m_vertices.begin(); while (m_vertex_it != m_vertices.end() && m_vertices.empty()) ++m_vertex_it; if (m_vertex_it != m_vertices.end()) m_edge_it = (*m_vertex_it).m_edges.begin(); } else { m_vertex_it = m_vertices.end(); } } template inline void Graph::edge_iterator::resetEdge() { if (m_vertex_it == m_vertices.end() || (*m_vertex_it).m_edges.empty()) { m_edge = Edge(); } else { m_edge = Edge((*m_vertex_it).m_data, (*m_edge_it).m_destination, (*m_edge_it).m_weight); } } template void Graph::edge_iterator::advance(int n) { while (n > 0 && m_vertex_it != m_vertices.end()) { const int edgesAhead = std::distance(m_edge_it, (*m_vertex_it).m_edges.end()) - 1; if (n <= edgesAhead) { std::advance(m_edge_it, n); return; } if (edgesAhead > 0) n -= edgesAhead; ++m_vertex_it; if (m_vertex_it != m_vertices.end()) { m_edge_it = (*m_vertex_it).m_edges.begin(); if (m_edge_it != (*m_vertex_it).m_edges.end()) --n; } } } // EdgeTo template inline Graph::EdgeTo::EdgeTo(const_reference destination, E weight) : m_destination(const_cast(&destination)) , m_weight(weight) {} template inline void Graph::EdgeTo::swap(EdgeTo& o) { std::swap(m_destination, o.m_destination); std::swap(m_weight, o.m_weight); } template inline bool Graph::EdgeTo::operator==(const EdgeTo& other) const { return m_destination == other.m_destination && m_weight == other.m_weight; } // Vertex template inline bool Graph::Vertex::operator==(const Vertex& other) const { return m_data == other.m_data && m_edges.size() == other.m_edges.size() && m_edges == other.m_edges; } template inline void Graph::Vertex::addEdge(const_reference destination, E weight) { m_edges.push_back(EdgeTo(destination, weight)); } template inline void Graph::Vertex::removeEdge(const_reference destination, E weight) { m_edges.erase(std::find_if(m_edges.begin(), m_edges.end(), [&destination, &weight](const EdgeTo& e) { return e.m_destination == destination && e.m_weight == weight;})); } template inline void Graph::Vertex::removeAllEdgesTo(const_reference destination) { std::remove_if(m_edges.begin(), m_edges.end(), [&destination](const EdgeTo& e) { return *e.m_destination == destination; }); } template inline std::vector::Edge> Graph::Vertex::edges() const { std::vector::Edge> retval; std::for_each(m_edges.begin(), m_edges.end(), [&retval, this](const EdgeTo& e) { retval.push_back(Edge(this->m_data, e.m_destination, e.m_weight)); }); return retval; } // Graph template inline typename Graph::size_type Graph::numberOfEdges() const { return std::accumulate(m_vertices.begin(), m_vertices.end(), 0, [](int sum, const Vertex& v) { return sum + v.m_edges.size(); }); } template inline bool Graph::addVertex(const_reference data) { if (find(data) != m_vertices.end()) return false; m_vertices.push_back(Vertex(data)); return true; } template inline bool Graph::removeVertex(const_reference data) { typename std::vector::iterator it = find(data); if (it == m_vertices.end()) return false; std::vector neighbours = neighboursOf(data); std::for_each(neighbours.begin(), neighbours.end(), [this, &data] (pointer vertex) { this->removeAllEdges(*vertex, data); } ); m_vertices.erase(it); return true; } template bool Graph::addEdge(const_reference source, const_reference 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); if (!m_directed) (*destination_it).addEdge(source, weight); return true; } template inline bool Graph::removeEdge(const_reference source, const_reference 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).removeEdge(destination, weight); if (!m_directed) (*destination_it).removeEdge(source, weight); return true; } template inline bool Graph::removeAllEdges(const_reference source, const_reference destination) { 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).removeAllEdgesTo(destination); if (!m_directed) (*destination_it).removeAllEdgesTo(source); return true; } template inline std::vector::pointer> 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::pointer> Graph::neighboursOf(const_reference data) const { typename std::vector retval; typename std::vector::const_iterator vertex_it = find(data); if (vertex_it == m_vertices.end()) return retval; std::set tmp; std::for_each((*vertex_it).m_edges.begin(), (*vertex_it).m_edges.end(), [&tmp, &retval](const EdgeTo& e) { if (tmp.insert(e.m_destination).second) retval.push_back(e.m_destination); }); return retval; } template std::vector Graph::edgesBetween(const_reference source, const_reference 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 EdgeTo& e) { if (*(e.m_destination) == destination) retval.push_back(e.m_weight); }); return retval; } template inline std::vector::Edge> Graph::edges() const { std::vector::Edge> retval; std::for_each(m_vertices.begin(), m_vertices.end(), [&retval](const Vertex& v) { const std::vector e = v.edges(); retval.insert(retval.end(), e.begin(), e.end()); }); return retval; } template inline typename std::vector::Vertex >::const_iterator Graph::find(const_reference data) const { return std::find_if(m_vertices.begin(), m_vertices.end(), [&data](const Vertex& v) { return *(v.m_data) == data; }); } template inline typename std::vector::Vertex >::iterator Graph::find(const_reference data) { return std::find_if(m_vertices.begin(), m_vertices.end(), [&data](const Vertex& v) { return *(v.m_data) == data; }); } #endif // GRAPH_H