#ifndef DIJKSTRA_H #define DIJKSTRA_H #include #include #include #include #include "DijkstraStructs.h" #include "../../misc/Debug.h" #include "../../misc/Time.h" #include template class Dijkstra { /** all allocated nodes for the user-data inputs */ std::unordered_map*> nodes; /** all already processed edges */ std::unordered_set> usedEdges; /** to-be-processed nodes (NOTE: using std::list here was SLOWER!) */ std::vector*> toBeProcessedNodes; public: /** get the dijkstra-pendant for the given user-node */ DijkstraNode* getNode(const T& userNode) { return nodes[&userNode]; } /** build shortest path from start to end using the provided wrapper-class */ template void build(const T& start, const T& end, const Access& acc) { // NOTE: end is currently ignored! // runs until all nodes were evaluated // compare two nodes by their distance from the start static auto comp = [] (const DijkstraNode* n1, const DijkstraNode* n2) {return n1->cumWeight < n2->cumWeight;}; Log::add("Dijkstra", "calculating dijkstra from " + (std::string)start + " to ALL OTHER nodes"); // cleanup toBeProcessedNodes.clear(); usedEdges.clear(); nodes.clear(); // run from start const T* cur = &start; // create a node for the start element DijkstraNode* dnStart = getNode(cur); dnStart->cumWeight = 0; // add this node to the processing list toBeProcessedNodes.push_back(dnStart); // until we are done while(!toBeProcessedNodes.empty()) { // get the next to-be-processed node const auto min = std::min_element(toBeProcessedNodes.begin(), toBeProcessedNodes.end(), comp); DijkstraNode* dnSrc = *min; // stop when end was reached?? //if (dnSrc->element == &end) {break;} // and remove him from the list toBeProcessedNodes.erase(min); // process each neighbor of the current element for (int i = 0; i < acc.getNumNeighbors(*dnSrc->element); ++i) { // get the neighbor itself const T* dst = acc.getNeighbor(*dnSrc->element, i); // get the distance-weight to the neighbor const float weight = acc.getWeightBetween(*dnSrc->element, *dst); _assertTrue(weight >= 0, "edge-weight must not be negative!"); // get-or-create a node for the neighbor DijkstraNode* dnDst = getNode(dst); // get-or-create the edge describing the connection const DijkstraEdge edge = getEdge(dnSrc, dnDst); // was this edge already processed? -> skip it if (usedEdges.find(edge) != usedEdges.end()) {continue;} // otherwise: remember it usedEdges.insert(edge); // and add the node for later processing toBeProcessedNodes.push_back(dnDst); // update the weight to the destination? const float potentialWeight = dnSrc->cumWeight + weight; if (potentialWeight < dnDst->cumWeight) { dnDst->cumWeight = potentialWeight; dnDst->previous = dnSrc; } } } // reclaim temporal memory toBeProcessedNodes.clear(); usedEdges.clear(); Log::add("Dijkstra", "processed " + std::to_string(nodes.size()) + " nodes"); } private: /** get (or create) a new node for the given user-node */ inline DijkstraNode* getNode(const T* userNode) { if (nodes.find(userNode) == nodes.end()) { DijkstraNode* dn = new DijkstraNode(userNode); nodes[userNode] = dn; } return nodes[userNode]; } /** get the edge (bi-directional) between the two given nodes */ inline DijkstraEdge getEdge(const DijkstraNode* n1, const DijkstraNode* n2) const { return DijkstraEdge(n1, n2); } }; #endif // DIJKSTRA_H