From fa7c830ff67ee171db837bce1fa944c76fe0cd4b Mon Sep 17 00:00:00 2001 From: dmatetelki Date: Tue, 1 Jul 2014 13:12:01 +0200 Subject: [PATCH] switching to unordered_map --- lib/graph/graph.hpp | 254 ++++++++++++-------------------------------- 1 file changed, 68 insertions(+), 186 deletions(-) diff --git a/lib/graph/graph.hpp b/lib/graph/graph.hpp index 47a80d8..c7bb0b5 100644 --- a/lib/graph/graph.hpp +++ b/lib/graph/graph.hpp @@ -1,8 +1,8 @@ #ifndef GRAPH_H #define GRAPH_H +#include #include -#include #include #include @@ -25,53 +25,29 @@ public: typedef E weight_type; typedef const E& const_weight_reference; - class Edge; class vertex_iterator; class edge_iterator; private: - struct Vertex; - typedef std::vector v_container; + struct EdgeTo; + typedef std::unordered_map > v_container; typedef typename v_container::iterator v_iterator; typedef typename v_container::const_iterator v_const_iterator; struct EdgeTo { EdgeTo() = delete; - EdgeTo(v_const_iterator destination, const_weight_reference weight = weight_type()); + EdgeTo(v_iterator destination, const_weight_reference weight = weight_type()); 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& o) const; - v_const_iterator m_destination; + v_iterator m_destination; weight_type m_weight; }; - struct Vertex { - - Vertex(const_reference data) : m_data(data), m_edges() {} - Vertex() : m_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& o) const; - - // parallell accumulate requires both - Vertex(size_type) : Vertex() {} - explicit operator int() const { return (int)m_edges.size(); } - - void addEdge(v_const_iterator destination, const_weight_reference weight = weight_type()); - void removeEdge(v_const_iterator destination, const_weight_reference weight = weight_type()); - void removeAllEdgesTo(v_const_iterator destination); - std::vector edges() const; - - value_type m_data; - std::list m_edges; - }; - public: struct Edge { @@ -115,7 +91,6 @@ public: /// @todo rename Vertex & Edge? // Modifiers - void reserveVertexCapacity(int c) { m_vertices.reserve(c); } void clear() { m_vertices.clear(); } void addVertex(const_reference data); @@ -125,7 +100,7 @@ public: void removeEdges(const_reference source, const_reference destination); // Lookup - bool contains(const_reference data) const { return find(data) != m_vertices.end(); } + bool contains(const_reference data) const { return m_vertices.find(data) != m_vertices.end(); } std::vector vertices() const; std::vector neighboursOf(const_reference data) const; std::vector weights(const_reference source, const_reference destination) const; @@ -153,8 +128,8 @@ public: reference_self_type operator=(self_type o) { swap(o); return *this; } void swap(reference_self_type o) { std::swap(m_it, o.m_it); } - const_reference operator*() { return m_it->m_data; } - const_pointer operator->() { return &m_it->m_data; } + const_reference operator*() { return m_it->first; } + const_pointer operator->() { return &m_it->first; } 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; } @@ -209,7 +184,7 @@ public: v_container m_vertices; v_iterator m_vertex_it; - typename std::list::iterator m_edge_it; + typename std::vector::iterator m_edge_it; Edge m_edge; }; @@ -219,14 +194,9 @@ public: const edge_iterator edge_end() const { return edge_iterator(m_vertices, false); } private: - v_const_iterator find(const_reference data) const; - v_iterator find(const_reference data); - v_const_iterator findAndCheck(const_reference data, bool existence_expected = true) const; - v_iterator findAndCheck(const_reference data, bool existence_expected = true); - /// @todo make is a vector specializetion - void adjustIteratorsAfter(v_iterator vit); - void resizeVerticesVector(); + static void eraseEdge(typename std::vector& v, const_reference data); + static void eraseEdge(typename std::vector& v, const_reference data, const_weight_reference weight); const bool m_directed; v_container m_vertices; @@ -298,7 +268,7 @@ inline Graph::edge_iterator::edge_iterator(v_container vertices, bool begi ++m_vertex_it; if (m_vertex_it != m_vertices.end()) - m_edge_it = m_vertex_it->m_edges.begin(); + m_edge_it = m_vertex_it->second.begin(); } else { m_vertex_it = m_vertices.end(); } @@ -307,10 +277,10 @@ inline Graph::edge_iterator::edge_iterator(v_container vertices, bool begi template inline void Graph::edge_iterator::resetEdge() { - if (m_vertex_it == m_vertices.end() || (*m_vertex_it).m_edges.empty()) { + if (m_vertex_it == m_vertices.end() || m_vertex_it->second.empty()) { m_edge = Edge(); } else { - m_edge = Edge( m_vertex_it->m_data, (m_edge_it->m_destination)->m_data, m_edge_it->m_weight); + m_edge = Edge( m_vertex_it->first, (m_edge_it->m_destination)->first, m_edge_it->m_weight); } } @@ -318,7 +288,7 @@ 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; + const int edgesAhead = std::distance(m_edge_it, m_vertex_it->second.end()) - 1; if (n <= edgesAhead) { std::advance(m_edge_it, n); return; @@ -328,8 +298,8 @@ void Graph::edge_iterator::advance(int n) ++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()) + m_edge_it = m_vertex_it->second.begin(); + if (m_edge_it != m_vertex_it->second.end()) --n; } } @@ -337,7 +307,7 @@ void Graph::edge_iterator::advance(int n) // EdgeTo template -inline Graph::EdgeTo::EdgeTo(v_const_iterator destination, const_weight_reference weight) +inline Graph::EdgeTo::EdgeTo(v_iterator destination, const_weight_reference weight) : m_destination(destination) , m_weight(weight) {} @@ -356,63 +326,12 @@ inline bool Graph::EdgeTo::operator==(const EdgeTo& other) const 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(v_const_iterator destination, const_weight_reference weight) -{ - m_edges.push_back(EdgeTo(destination, weight)); -} - -template -inline void Graph::Vertex::removeEdge(v_const_iterator destination, const_weight_reference weight) -{ - typename std::list::iterator it = - std::find_if(m_edges.begin(), m_edges.end(), - [&destination, &weight](const EdgeTo& e) - { return e.m_destination == destination && e.m_weight == weight;}); - - if (it != m_edges.end()) - m_edges.erase(it); -} - -template -inline void Graph::Vertex::removeAllEdgesTo(v_const_iterator destination) -{ - m_edges.erase( - std::remove_if(m_edges.begin(), m_edges.end(), - [&destination](const EdgeTo& e) - { return e.m_destination == destination; }), - m_edges.end()); -} - -template -inline std::vector::Edge> Graph::Vertex::edges() const -{ - std::vector::Edge> retval; - for (const EdgeTo& e : m_edges) - retval.push_back(Edge(m_data, (e.m_destination)->m_data, e.m_weight)); - - return retval; -} - - // Graph template Graph::Graph(std::initializer_list vertex_list) : Graph() { - reserveVertexCapacity(vertex_list.size()); for(const V& v : vertex_list) addVertex(v); } @@ -421,8 +340,6 @@ template Graph::Graph(std::initializer_list edge_list) : Graph() { -// m_vertices.resize(edge_list.size()); -// m_vertices.resize(2); for (const Edge& e : edge_list ) addEdge(e.source, e.destination, e.weight); } @@ -430,36 +347,38 @@ Graph::Graph(std::initializer_list edge_list) 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(); }); + int sum = 0; + for (const auto& v : m_vertices) + sum += v.second.size(); + + return sum; } template inline void Graph::addVertex(const_reference data) { - if (find(data) != m_vertices.end()) + if (m_vertices.find(data) != m_vertices.end()) return; - if (m_vertices.size() == m_vertices.capacity()) - resizeVerticesVector(); - - m_vertices.push_back(Vertex(data)); + std::pair::EdgeTo> > p(data, std::vector()); + m_vertices.insert(p); } template inline void Graph::removeVertex(const_reference data) { - v_iterator it = find(data); + v_iterator it = m_vertices.find(data); if (it == m_vertices.end()) return; - std::for_each(m_vertices.begin(), m_vertices.end(), - [&it] (Vertex& v) - { v.removeAllEdgesTo(it); } ); + if (m_directed) + for (auto &v : m_vertices) + eraseEdge(v.second, data); + else + for (EdgeTo& n : it->second) + eraseEdge(n.m_destination->second, data); m_vertices.erase(it); - adjustIteratorsAfter(it); } template @@ -468,52 +387,52 @@ void Graph::addEdge(const_reference source, const_reference destination, c addVertex(source); addVertex(destination); - v_iterator source_it = find(source); - v_iterator destination_it = find(destination); + v_iterator source_it = m_vertices.find(source); + v_iterator destination_it = m_vertices.find(destination); - source_it->addEdge(destination_it, weight); + source_it->second.push_back(Graph::EdgeTo(destination_it, weight)); if (!m_directed && source != destination) - destination_it->addEdge(source_it, weight); + destination_it->second.push_back(Graph::EdgeTo(source_it, weight)); } template inline void Graph::removeEdge(const_reference source, const_reference destination, const_weight_reference weight) { - v_iterator source_it = find(source); + v_iterator source_it = m_vertices.find(source); if (source_it == m_vertices.end()) return; - v_iterator destination_it = find(destination); + v_iterator destination_it = m_vertices.find(destination); if (destination_it == m_vertices.end()) return; - source_it->removeEdge(destination_it, weight); + eraseEdge(source_it->second, destination, weight); if (!m_directed) - destination_it->removeEdge(source_it, weight); + eraseEdge(destination_it->second, source, weight); } template inline void Graph::removeEdges(const_reference source, const_reference destination) { - v_iterator source_it = find(source); + v_iterator source_it = m_vertices.find(source); if (source_it == m_vertices.end()) return; - v_iterator destination_it = find(destination); + v_iterator destination_it = m_vertices.find(destination); if (destination_it == m_vertices.end()) return; - source_it->removeAllEdgesTo(destination_it); + eraseEdge(source_it->second, destination); if (!m_directed) - destination_it->removeAllEdgesTo(source_it); + eraseEdge(destination_it->second, source); } template inline std::vector::value_type> Graph::vertices() const { std::vector retval; - for (const Vertex& v : m_vertices) - retval.push_back(v.m_data); + for (const auto& v : m_vertices) + retval.push_back(v.first); return retval; } @@ -522,14 +441,14 @@ template std::vector::value_type> Graph::neighboursOf(const_reference data) const { typename std::vector retval; - v_const_iterator vertex_it = find(data); - if (vertex_it == m_vertices.end() || vertex_it->m_edges.empty()) + v_const_iterator vertex_it = m_vertices.find(data); + if (vertex_it == m_vertices.end() || vertex_it->second.empty()) return retval; - std::set tmp; - for (const EdgeTo& e : vertex_it->m_edges) - if (tmp.insert(e.m_destination).second) - retval.push_back((e.m_destination)->m_data); + std::set tmp; + for (const EdgeTo& e : vertex_it->second) + if (tmp.insert(e.m_destination->first).second) + retval.push_back(e.m_destination->first); return retval; } @@ -538,15 +457,15 @@ template std::vector Graph::weights(const_reference source, const_reference destination) const { std::vector retval; - v_const_iterator vertex_it = find(source); + v_const_iterator vertex_it = m_vertices.find(source); if (vertex_it == m_vertices.end()) return retval; - if (find(destination) == m_vertices.end()) + if (m_vertices.find(destination) == m_vertices.end()) return retval; - for (const EdgeTo& e : vertex_it->m_edges) - if (e.m_destination->m_data == destination) + for (const EdgeTo& e : vertex_it->second) + if (e.m_destination->first == destination) retval.push_back(e.m_weight); return retval; @@ -556,62 +475,25 @@ template inline std::vector::Edge> Graph::edges() const { std::vector::Edge> retval; - for (const Vertex& v : m_vertices) { - const std::vector e = v.edges(); - retval.insert(retval.end(), e.begin(), e.end()); - } + for (const auto& v : m_vertices) + for (const auto& e : v.second) + retval.push_back(Graph::Edge(v.first, (e.m_destination)->first, e.m_weight)); return retval; } - -template -inline typename Graph::v_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 Graph::v_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; }); +void Graph::eraseEdge(typename std::vector& v, const_reference data) { + v.erase(std::remove_if(v.begin(), v.end(), + [&data](const EdgeTo& e) { return e.m_destination->first == data; } ), + v.end()); } template -void Graph::adjustIteratorsAfter(v_iterator deleted_vit) -{ - std::for_each(m_vertices.begin(), m_vertices.end(), - [&deleted_vit](Vertex& v) - { for (EdgeTo& e : v.m_edges) - if (e.m_destination > deleted_vit) - --e.m_destination; - }); -} - -template -void Graph::resizeVerticesVector() -{ - const float grow_factor = 1.5; - const int old_size = m_vertices.size(); - const int new_size = old_size == 0 ? 1 : old_size * grow_factor + 0.5; - - std::vector old_vertices = vertices(); - std::vector old_edges = edges(); - - clear(); - reserveVertexCapacity(new_size); - - for(auto v: old_vertices) - addVertex(v); - - for(auto e: old_edges) - addEdge(e.source, e.destination, e.weight); +void Graph::eraseEdge(typename std::vector& v, const_reference data, const_weight_reference weight ) { + v.erase(std::remove_if(v.begin(), v.end(), + [&data, &weight](const EdgeTo& e) { return e.m_destination->first == data && e.m_weight == weight; } ), + v.end()); } #endif // GRAPH_H