You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

581 lines
19 KiB

#ifndef GRAPH_H
#define GRAPH_H
#include <vector>
#include <list>
#include <set>
#include <algorithm>
#include <iterator>
#include <memory>
template <typename V,
typename E = int,
typename Alloc = std::allocator<V> >
class Graph {
private:
struct Vertex;
struct 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;
class Edge {
public:
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);
reference getSource() const { return *m_source; }
reference getDestination() const { return *m_destination; }
E getWeight() const { return m_weight; }
private:
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(), m_allocator(Alloc()) {}
Graph(const Graph<V, E, Alloc>& o) : m_directed(o.m_directed), m_vertices(o.m_vertices), m_allocator(o.m_allocator) {}
Graph<V, E, Alloc>& operator=(Graph<V, E, Alloc> o) { swap(o); return *this; }
void swap(Graph& o) { std::swap (m_directed, o.m_directed); std::swap(m_vertices, o.m_vertices); std::swap(m_allocator, o.m_allocator);}
// 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;
void resize(size_type size) { m_vertices.resize(size); }
// Modifiers
bool addVertex(const_reference data);
bool removeVertex(const_reference data);
bool addEdge(const_reference source, const_reference destination, E weight = 0);
bool removeEdge(const_reference source, const_reference destination, E 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<const_pointer> vertices() const;
std::vector<const_pointer> neighboursOf(const_reference data) const;
std::vector<E> weightsBetween(const_reference source, const_reference destination) const;
std::vector<Edge> edges() const;
// iterators
class vertex_iterator : public std::iterator<std::forward_iterator_tag,
value_type,
difference_type,
pointer,
reference>
{
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<Vertex>::iterator it) : m_it(it) {}
vertex_iterator(typename std::vector<Vertex>::const_iterator it) : m_it(it) {}
typename std::vector<Vertex>::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<std::forward_iterator_tag,
Edge,
difference_type,
edge_pointer,
edge_reference>
{
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<Vertex> vertices, bool begin = true);
void resetEdge();
void advance(int n);
std::vector<Vertex> m_vertices;
typename std::vector<Vertex>::iterator m_vertex_it;
typename std::list<EdgeTo>::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, Alloc allocator);
Vertex(const Vertex& o);
~Vertex();
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); std::swap(m_allocator, o.m_allocator);}
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<Edge> edges() const;
pointer m_data;
std::list<EdgeTo> m_edges;
Alloc& m_allocator;
};
typename std::vector<Vertex >::const_iterator find(const_reference data) const;
typename std::vector<Vertex >::iterator find(const_reference data);
bool m_directed;
std::vector<Vertex> m_vertices;
Alloc m_allocator;
};
// Edge
template <typename V, typename E, typename Alloc>
inline Graph<V, E, Alloc>::Edge::Edge(pointer source, pointer destination, E weight)
: m_source(source)
, m_destination(destination)
, m_weight(weight)
{}
template <typename V, typename E, typename Alloc>
inline Graph<V, E, Alloc>::Edge::Edge(const Edge& o)
: m_source(o.m_source)
, m_destination(o.m_destination)
, m_weight(o.m_weight)
{}
template <typename V, typename E, typename Alloc>
inline void Graph<V, E, Alloc>::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 <typename V, typename E, typename Alloc>
inline Graph<V, E, Alloc>::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 <typename V, typename E, typename Alloc>
bool Graph<V, E, Alloc>::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 <typename V, typename E, typename Alloc>
inline void Graph<V, E, Alloc>::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 <typename V, typename E, typename Alloc>
inline Graph<V, E, Alloc>::edge_iterator::edge_iterator(std::vector<Vertex> 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 <typename V, typename E, typename Alloc>
inline void Graph<V, E, Alloc>::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 <typename V, typename E, typename Alloc>
void Graph<V, E, Alloc>::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 <typename V, typename E, typename Alloc>
inline Graph<V, E, Alloc>::EdgeTo::EdgeTo(const_reference destination, E weight)
: m_destination(const_cast<pointer>(&destination))
, m_weight(weight)
{}
template <typename V, typename E, typename Alloc>
inline void Graph<V, E, Alloc>::EdgeTo::swap(EdgeTo& o)
{
std::swap(m_destination, o.m_destination);
std::swap(m_weight, o.m_weight);
}
template <typename V, typename E, typename Alloc>
inline bool Graph<V, E, Alloc>::EdgeTo::operator==(const EdgeTo& other) const
{
return m_destination == other.m_destination &&
m_weight == other.m_weight;
}
// Vertex
template <typename V, typename E, typename Alloc>
inline Graph<V, E, Alloc>::Vertex::Vertex(const_reference data, Alloc allocator)
: m_data()
, m_edges()
, m_allocator(allocator)
{
m_data = m_allocator.allocate(1);
m_allocator.construct(m_data, data);
}
template <typename V, typename E, typename Alloc>
inline Graph<V, E, Alloc>::Vertex::Vertex(const Vertex& o)
: m_data()
, m_edges(o.m_edges)
, m_allocator(o.m_allocator)
{
m_data = m_allocator.allocate(1);
m_allocator.construct(m_data, *(o.m_data));
}
template <typename V, typename E, typename Alloc>
inline Graph<V, E, Alloc>::Vertex::~Vertex()
{
m_allocator.destroy(m_data);
m_allocator.deallocate(m_data, 1);
}
template <typename V, typename E, typename Alloc>
inline bool Graph<V, E, Alloc>::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 <typename V, typename E, typename Alloc>
inline void Graph<V, E, Alloc>::Vertex::addEdge(const_reference destination, E weight)
{
m_edges.push_back(EdgeTo(destination, weight));
}
template <typename V, typename E, typename Alloc>
inline void Graph<V, E, Alloc>::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 <typename V, typename E, typename Alloc>
inline void Graph<V, E, Alloc>::Vertex::removeAllEdgesTo(const_reference destination)
{
std::remove_if(m_edges.begin(), m_edges.end(),
[&destination](const EdgeTo& e)
{ return *e.m_destination == destination; });
}
template <typename V, typename E, typename Alloc>
inline std::vector<typename Graph<V, E, Alloc>::Edge> Graph<V, E, Alloc>::Vertex::edges() const
{
std::vector<Graph<V, E, Alloc>::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 <typename V, typename E, typename Alloc>
inline typename Graph<V, E, Alloc>::size_type Graph<V, E, Alloc>::numberOfEdges() const
{
return std::accumulate(m_vertices.begin(), m_vertices.end(), 0,
[](int sum, const Vertex& v)
{ return sum + v.m_edges.size(); });
}
template <typename V, typename E, typename Alloc>
inline bool Graph<V, E, Alloc>::addVertex(const_reference data)
{
if (find(data) != m_vertices.end())
return false;
m_vertices.push_back(Vertex(data, m_allocator));
return true;
}
template <typename V, typename E, typename Alloc>
inline bool Graph<V, E, Alloc>::removeVertex(const_reference data)
{
typename std::vector<Vertex>::iterator it = find(data);
if (it == m_vertices.end())
return false;
std::vector<const_pointer> neighbours = neighboursOf(data);
std::for_each(neighbours.begin(), neighbours.end(),
[this, &data] (const_pointer vertex)
{ this->removeAllEdges(*vertex, data); } );
m_vertices.erase(it);
return true;
}
template <typename V, typename E, typename Alloc>
bool Graph<V, E, Alloc>::addEdge(const_reference source, const_reference destination, E weight)
{
typename std::vector<Vertex>::iterator source_it = find(source);
if (source_it == m_vertices.end())
return false;
typename std::vector<Vertex>::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 <typename V, typename E, typename Alloc>
inline bool Graph<V, E, Alloc>::removeEdge(const_reference source, const_reference destination, E weight)
{
typename std::vector<Vertex>::iterator source_it = find(source);
if (source_it == m_vertices.end())
return false;
typename std::vector<Vertex>::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 <typename V, typename E, typename Alloc>
inline bool Graph<V, E, Alloc>::removeAllEdges(const_reference source, const_reference destination)
{
typename std::vector<Vertex>::iterator source_it = find(source);
if (source_it == m_vertices.end())
return false;
typename std::vector<Vertex>::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 <typename V, typename E, typename Alloc>
inline std::vector<typename Graph<V, E, Alloc>::const_pointer> Graph<V, E, Alloc>::vertices() const
{
std::vector<const_pointer> retval;
std::for_each(m_vertices.begin(), m_vertices.end(),
[&retval](const Vertex& v)
{ retval.push_back(v.m_data); });
return retval;
}
template <typename V, typename E, typename Alloc>
std::vector<typename Graph<V, E, Alloc>::const_pointer> Graph<V, E, Alloc>::neighboursOf(const_reference data) const
{
typename std::vector<const_pointer> retval;
typename std::vector<Vertex >::const_iterator vertex_it = find(data);
if (vertex_it == m_vertices.end())
return retval;
std::set<pointer> 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 <typename V, typename E, typename Alloc>
std::vector<E> Graph<V, E, Alloc>::weightsBetween(const_reference source, const_reference destination) const
{
std::vector<E> retval;
typename std::vector<Vertex>::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 <typename V, typename E, typename Alloc>
inline std::vector<typename Graph<V, E, Alloc>::Edge> Graph<V, E, Alloc>::edges() const
{
std::vector<typename Graph<V, E, Alloc>::Edge> retval;
std::for_each(m_vertices.begin(), m_vertices.end(),
[&retval](const Vertex& v)
{ const std::vector<Edge> e = v.edges();
retval.insert(retval.end(), e.begin(), e.end());
});
return retval;
}
template <typename V, typename E, typename Alloc>
inline typename std::vector<typename Graph<V, E, Alloc>::Vertex >::const_iterator Graph<V, E, Alloc>::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 <typename V, typename E, typename Alloc>
inline typename std::vector<typename Graph<V, E, Alloc>::Vertex >::iterator Graph<V, E, Alloc>::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