making dist and prev maps into 1, as they are accessed together always, for performance reasons.

master
dmatetelki 10 years ago
parent fcd4c4ff30
commit 1a64773a66

@ -7,35 +7,38 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <queue> #include <queue>
#include <set>
#include <utility> #include <utility>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <type_traits>
namespace { namespace {
template <typename V, typename W> template <typename V, typename W>
inline V closestNode(const std::unordered_set<V>& q, const std::unordered_map<V, W>& dist) inline V closestNode(const std::unordered_set<V>& q, const std::unordered_map<V, std::pair<W, V> >& dist_prev)
{ {
const typename std::unordered_set<V>::const_iterator smallest_it = const typename std::unordered_set<V>::const_iterator smallest_it =
std::min_element(q.begin(), q.end(), std::min_element(q.begin(), q.end(),
[&dist](const V& v1, const V& v2) [&dist_prev](const V& v1, const V& v2)
{ return !( dist.find(v2) != dist.end() && { const auto v1_it = dist_prev.find(v1);
((dist.find(v1) == dist.end()) || (dist.at(v1) > dist.at(v2))) ); } ); 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; return *smallest_it;
} }
template <typename V> template <typename V, typename W>
std::vector<V> pathFromPrevList(const V& dest, std::unordered_map<V, V> prev) std::vector<V> pathFromPrevList(const V& dest, const std::unordered_map<V, std::pair<W, V> >& dist_prev)
{ {
std::vector<V> retval; std::vector<V> retval;
if (prev.find(dest) == prev.end()) if (dist_prev.find(dest) == dist_prev.end())
return retval; return retval;
V it = dest; 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);
} }
retval.push_back(it); retval.push_back(it);
@ -54,39 +57,36 @@ dijkstra_shortest_path_to(const Graph<V>& graph,
const V& dest, const V& dest,
std::function<W(V, V)> distanceCompute) std::function<W(V, V)> distanceCompute)
{ {
std::unordered_map<V, W> dist; std::unordered_map<V, std::pair<W, V> > dist_prev;
std::unordered_map<V, V> prev;
dist.emplace(source, W()); dist_prev.emplace(source, std::pair<W, V>(W(), V()));
std::unordered_set<V> q; std::unordered_set<V> q;
for (const auto& v : graph.neighboursOf(source)) { for (const auto& v : graph.neighboursOf(source)) {
q.insert(v); q.insert(v);
dist[v] = distanceCompute(source, v); dist_prev.emplace(v, std::pair<W, V>(distanceCompute(source, v), source));
prev[v] = source;
} }
while (!q.empty()) { while (!q.empty()) {
const V& u = closestNode<V, W>(q, dist); const V& u = closestNode<V, W>(q, dist_prev);
q.erase(u); q.erase(u);
if (u == dest) if (u == dest)
break; break;
for (V v : graph.neighboursOf(u)) { for (const auto& v : graph.neighboursOf(u)) {
const W d = distanceCompute(u, v); 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 if (dist_prev.find(v) == dist_prev.end()) { // new node
dist.emplace(v, alt); dist_prev.emplace(v, std::pair<W, V>(alt, u));
prev.emplace(v, u);
q.insert(v); q.insert(v);
} else if (alt < dist.at(v)) { // better route } else if (alt < dist_prev.at(v).first) { // better route
dist[v] = alt; dist_prev[v] = std::pair<W, V>(alt, u);
prev[v] = u;
} }
} }
} }
return pathFromPrevList(dest, prev); return pathFromPrevList(dest, dist_prev);
} }
#endif // GRAPH_ALGORITHMS_HPP #endif // GRAPH_ALGORITHMS_HPP

@ -5,6 +5,8 @@
#include "fixture.hpp" #include "fixture.hpp"
#include <iostream>
void printPath(std::size_t number_of_rows, void printPath(std::size_t number_of_rows,
std::size_t number_of_columns, std::size_t number_of_columns,
float2 source, float2 source,
@ -48,7 +50,7 @@ TEST_CASE("Graph algorithms, small", "[graph][algorithm][dijkstra]" ) {
Graph<int> g; Graph<int> g;
const int source(0); const int source(0);
const int destination(1); const int destination(1);
const std::vector<int> shortestPath = dijkstra_shortest_path_to<int, int>(g, source, destination, std::distanceOf2ints()); const std::vector<int> shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints());
REQUIRE( shortestPath.size() == 0 ); REQUIRE( shortestPath.size() == 0 );
} }
@ -56,7 +58,7 @@ TEST_CASE("Graph algorithms, small", "[graph][algorithm][dijkstra]" ) {
Graph<int> g = { {1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4} }; Graph<int> g = { {1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4} };
const int source(1); const int source(1);
const int destination(10); const int destination(10);
const std::vector<int> shortestPath = dijkstra_shortest_path_to<int, int>(g, source, destination, std::distanceOf2ints()); const std::vector<int> shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints());
REQUIRE( shortestPath.size() == 0 ); REQUIRE( shortestPath.size() == 0 );
} }
@ -64,7 +66,7 @@ TEST_CASE("Graph algorithms, small", "[graph][algorithm][dijkstra]" ) {
Graph<int> g = { {1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4} }; Graph<int> g = { {1, 2}, {1, 3}, {1, 4}, {2, 4}, {3, 4} };
const int source(10); const int source(10);
const int destination(1); const int destination(1);
const std::vector<int> shortestPath = dijkstra_shortest_path_to<int, int>(g, source, destination, std::distanceOf2ints()); const std::vector<int> shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints());
REQUIRE( shortestPath.size() == 0 ); REQUIRE( shortestPath.size() == 0 );
} }
@ -72,7 +74,7 @@ TEST_CASE("Graph algorithms, small", "[graph][algorithm][dijkstra]" ) {
Graph<int> g = { {1, 2}, {3, 4} }; Graph<int> g = { {1, 2}, {3, 4} };
const int source(1); const int source(1);
const int destination(4); const int destination(4);
const std::vector<int> shortestPath = dijkstra_shortest_path_to<int, int>(g, source, destination, std::distanceOf2ints()); const std::vector<int> shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2ints());
REQUIRE( shortestPath.size() == 0 ); REQUIRE( shortestPath.size() == 0 );
} }
@ -84,7 +86,7 @@ TEST_CASE("Graph algorithms, small", "[graph][algorithm][dijkstra]" ) {
const float2 source(0, 0); const float2 source(0, 0);
const float2 destination(2, 2); const float2 destination(2, 2);
const std::vector<float2> shortestPath = dijkstra_shortest_path_to<float2, float>(g, source, destination, std::distanceOf2float2s()); const std::vector<float2> 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)); const float euclidan_distance = sqrt(pow(source.x - destination.x, 2) + pow(source.y - destination.y, 2));
REQUIRE( std::distanceOf2float2s()(source, destination) == euclidan_distance ); REQUIRE( std::distanceOf2float2s()(source, destination) == euclidan_distance );
@ -112,7 +114,7 @@ TEST_CASE_METHOD(Fixture<float2>, "Graph algorithms, big graph", "[graph][algori
const float2 source(0, 0); const float2 source(0, 0);
const float2 destination(number_of_rows-1, number_of_columns-1); const float2 destination(number_of_rows-1, number_of_columns-1);
const std::vector<float2> shortestPath = dijkstra_shortest_path_to<float2, float>(g, source, destination, std::distanceOf2float2s()); const std::vector<float2> shortestPath = dijkstra_shortest_path_to(g, source, destination, std::distanceOf2float2s());
REQUIRE( shortestPath.size() == number_of_rows); REQUIRE( shortestPath.size() == number_of_rows);
for (std::size_t i = 0; i < number_of_rows; ++i) for (std::size_t i = 0; i < number_of_rows; ++i)

Loading…
Cancel
Save