diff --git a/lib/graph/graph_algorithms.hpp b/lib/graph/graph_algorithms.hpp index e928d1c..ad750bc 100644 --- a/lib/graph/graph_algorithms.hpp +++ b/lib/graph/graph_algorithms.hpp @@ -7,35 +7,38 @@ #include #include #include +#include #include #include #include +#include namespace { template -inline V closestNode(const std::unordered_set& q, const std::unordered_map& dist) +inline V closestNode(const std::unordered_set& q, const std::unordered_map >& dist_prev) { const typename std::unordered_set::const_iterator smallest_it = std::min_element(q.begin(), q.end(), - [&dist](const V& v1, const V& v2) - { return !( dist.find(v2) != dist.end() && - ((dist.find(v1) == dist.end()) || (dist.at(v1) > dist.at(v2))) ); } ); + [&dist_prev](const V& v1, const V& v2) + { const auto v1_it = dist_prev.find(v1); + const auto v2_it = dist_prev.find(v2); + return !( v2_it != dist_prev.end() && ((v1_it == dist_prev.end()) || (v1_it->second.first > v2_it->second.first)) ); } ); return *smallest_it; } -template -std::vector pathFromPrevList(const V& dest, std::unordered_map prev) +template +std::vector pathFromPrevList(const V& dest, const std::unordered_map >& dist_prev) { std::vector retval; - if (prev.find(dest) == prev.end()) + if (dist_prev.find(dest) == dist_prev.end()) return retval; V it = dest; - for (; prev.find(it) != prev.end() ; it = prev.at(it)) { + for (; it != V() ; it = dist_prev.at(it).second) { retval.push_back(it); } retval.push_back(it); @@ -54,39 +57,36 @@ dijkstra_shortest_path_to(const Graph& graph, const V& dest, std::function distanceCompute) { - std::unordered_map dist; - std::unordered_map prev; + std::unordered_map > dist_prev; - dist.emplace(source, W()); + dist_prev.emplace(source, std::pair(W(), V())); std::unordered_set q; for (const auto& v : graph.neighboursOf(source)) { q.insert(v); - dist[v] = distanceCompute(source, v); - prev[v] = source; + dist_prev.emplace(v, std::pair(distanceCompute(source, v), source)); } while (!q.empty()) { - const V& u = closestNode(q, dist); + const V& u = closestNode(q, dist_prev); q.erase(u); if (u == dest) break; - for (V v : graph.neighboursOf(u)) { + for (const auto& v : graph.neighboursOf(u)) { const W d = distanceCompute(u, v); - const W alt = dist.at(u) + d; + const W alt = dist_prev.at(u).first + d; - if (dist.find(v) == dist.end()) { // new node - dist.emplace(v, alt); - prev.emplace(v, u); + if (dist_prev.find(v) == dist_prev.end()) { // new node + dist_prev.emplace(v, std::pair(alt, u)); q.insert(v); - } else if (alt < dist.at(v)) { // better route - dist[v] = alt; - prev[v] = u; + } else if (alt < dist_prev.at(v).first) { // better route + dist_prev[v] = std::pair(alt, u); } } } - return pathFromPrevList(dest, prev); + return pathFromPrevList(dest, dist_prev); } + #endif // GRAPH_ALGORITHMS_HPP diff --git a/test/graph/test_graph_algorithms.cpp b/test/graph/test_graph_algorithms.cpp index 0a66e34..4379bbd 100644 --- a/test/graph/test_graph_algorithms.cpp +++ b/test/graph/test_graph_algorithms.cpp @@ -5,6 +5,8 @@ #include "fixture.hpp" +#include + void printPath(std::size_t number_of_rows, std::size_t number_of_columns, float2 source, @@ -48,7 +50,7 @@ TEST_CASE("Graph algorithms, small", "[graph][algorithm][dijkstra]" ) { Graph g; const int source(0); const int destination(1); - const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints()); + const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints()); REQUIRE( shortestPath.size() == 0 ); } @@ -56,7 +58,7 @@ TEST_CASE("Graph algorithms, small", "[graph][algorithm][dijkstra]" ) { Graph g = { {1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4} }; const int source(1); const int destination(10); - const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints()); + const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints()); REQUIRE( shortestPath.size() == 0 ); } @@ -64,7 +66,7 @@ TEST_CASE("Graph algorithms, small", "[graph][algorithm][dijkstra]" ) { Graph g = { {1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4} }; const int source(10); const int destination(1); - const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints()); + const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints()); REQUIRE( shortestPath.size() == 0 ); } @@ -72,7 +74,7 @@ TEST_CASE("Graph algorithms, small", "[graph][algorithm][dijkstra]" ) { Graph g = { {1, 2}, {3, 4} }; const int source(1); const int destination(4); - const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints()); + const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints()); REQUIRE( shortestPath.size() == 0 ); } @@ -84,7 +86,7 @@ TEST_CASE("Graph algorithms, small", "[graph][algorithm][dijkstra]" ) { const float2 source(0, 0); const float2 destination(2, 2); - const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2float2s()); + const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2float2s()); const float euclidan_distance = sqrt(pow(source.x - destination.x, 2) + pow(source.y - destination.y, 2)); REQUIRE( std::distanceOf2float2s()(source, destination) == euclidan_distance ); @@ -112,7 +114,7 @@ TEST_CASE_METHOD(Fixture, "Graph algorithms, big graph", "[graph][algori const float2 source(0, 0); const float2 destination(number_of_rows-1, number_of_columns-1); - const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2float2s()); + const std::vector shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2float2s()); REQUIRE( shortestPath.size() == number_of_rows); for (std::size_t i = 0; i < number_of_rows; ++i)