/* Retrieved from: http://en.literateprograms.org/Dijkstra's_algorithm_(C_Plus_Plus)?oldid=13422 */ #ifndef GRAPH_H #define GRAPH_H #include #include #include #include #include #undef min #undef max #include #define Max(a,b) (((a) > (b)) ? (a) : (b)) #define Min(a,b) (((a) < (b)) ? (a) : (b)) template class Graph { private: typedef VertexType vertex_t; typedef WeightType weight_t; public: struct Edge { vertex_t target; weight_t weight; unsigned int index; Edge(vertex_t arg_target, weight_t arg_weight, unsigned int edge_index = -1) : target(arg_target), weight(arg_weight), index(edge_index) { } bool operator == (const Edge & rhs) const { return (target == rhs.target && weight == rhs.weight && index == rhs.index); } }; struct CompareEdge{ bool operator()(const Edge &a, const Edge &b){ if (a.target < b.target) return true; if (a.target > b.target) return false; return a.index < b.index; } }; typedef std::set EdgesSet; private: typedef std::map > adjacency_map_t; typedef std::set vertices_set; template struct pair_first_less { bool operator()(std::pair p1, std::pair p2) const { if(p1.first == p2.first) { return p1.second < p2.second; } return p1.first < p2.first; } }; void DijkstraComputePaths(vertex_t source) { if(source == lastStart) return; else { lastStart = source; previous.clear(); } for (typename adjacency_map_t::iterator vertex_iter = adjacency_map.begin(); vertex_iter != adjacency_map.end(); vertex_iter++) { vertex_t v = vertex_iter->first; min_distance[v] = std::numeric_limits< WeightType >::infinity(); } min_distance[source] = 0; std::set< std::pair, pair_first_less > vertex_queue; for (typename adjacency_map_t::iterator vertex_iter = adjacency_map.begin(); vertex_iter != adjacency_map.end(); vertex_iter++){ vertex_t v = vertex_iter->first; vertex_queue.insert(std::pair(min_distance[v], v)); } while (!vertex_queue.empty()) { vertex_t u = vertex_queue.begin()->second; vertex_queue.erase(vertex_queue.begin()); // Visit each edge exiting u for (typename std::list::iterator edge_iter = adjacency_map[u].begin(); edge_iter != adjacency_map[u].end(); edge_iter++) { vertex_t v = edge_iter->target; weight_t weight = edge_iter->weight; weight_t distance_through_u = min_distance[u] + weight; if (distance_through_u < min_distance[v]) { vertex_queue.erase(std::pair(min_distance[v], v)); min_distance[v] = distance_through_u; previous[v] = u; vertex_queue.insert(std::pair(min_distance[v], v)); } } } } std::list DijkstraGetShortestPathTo(vertex_t target) { std::list path; typename std::map::iterator prev; vertex_t vertex = target; path.push_front(vertex); while((prev = previous.find(vertex)) != previous.end()) { vertex = prev->second; path.push_front(vertex); } return path; } public: std::list DijkstraShortestPath(vertex_t start, vertex_t end) { this->DijkstraComputePaths(start); return this->DijkstraGetShortestPathTo(end); } int NodeDistance(vertex_t n1, vertex_t n2) { if(!this->isConnected(n1, n2)) return -1; return DijkstraShortestPath(n1, n2).size(); } private: // Graph Variables: vertices_set vertices; adjacency_map_t adjacency_map; std::map min_distance; std::map previous; vertex_t lastStart; public: Graph() { lastStart = std::numeric_limits::max(); } Graph(const Graph& from) { this->adjacency_map = from.adjacency_map; this->vertices = from.vertices; this->min_distance = from.min_distance; this->previous = from.previous; this->lastStart = from.lastStart; } void AddEdge(vertex_t p1, vertex_t p2, weight_t weight, int index = -1) { adjacency_map[AddVertex(p1)].push_back(Edge(AddVertex(p2), weight, index)); adjacency_map[AddVertex(p2)].push_back(Edge(AddVertex(p1), weight, index)); } vertex_t AddVertex(vertex_t p) { vertices.insert(p); return p; } void removeDirectedEdge(vertex_t p1, vertex_t p2) { std::list * adj = &adjacency_map[p1]; for(typename std::list::iterator i = adj->begin(); i != adj->end(); i++) { Edge * e = &(*i); if(e->target == p2) { adj->remove(*e); return; } } } void removeEdge(vertex_t p1, vertex_t p2) { removeDirectedEdge(p1, p2); removeDirectedEdge(p2, p1); } void SetDirectedEdgeWeight(vertex_t p1, vertex_t p2, weight_t newWeight) { std::list * adj = &adjacency_map[p1]; for(typename std::list::iterator i = adj->begin(); i != adj->end(); i++) { Edge * e = &(*i); if(e->target == p2) { e->weight = newWeight; return; } } } void SetEdgeWeight(vertex_t p1, vertex_t p2, weight_t newWeight) { SetDirectedEdgeWeight(p1, p2, newWeight); SetDirectedEdgeWeight(p2, p1, newWeight); } vertex_t GetRandomNeighbour(vertex_t p) { return adjacency_map[p].front().target; } std::vector GetNeighbours(vertex_t p) { std::vector neighbours; std::list * adj = &adjacency_map[p]; for(typename std::list::iterator i = adj->begin(); i != adj->end(); i++) { Edge * e = &(*i); neighbours.push_back(e->target); } return neighbours; } vertex_t GetOtherNeighbour(vertex_t p, vertex_t q) { vertex_t n = p; std::list * adj = &adjacency_map[p]; for(typename std::list::iterator i = adj->begin(); i != adj->end(); i++) { Edge * e = &(*i); if(e->target != q) { n = e->target; break; } } return n; } bool isCircular(vertex_t p) { std::set visited; visited.insert(p); bool hasMore = true; vertex_t curr = p; vertex_t prev = p; while(hasMore) { vertex_t next = GetOtherNeighbour(curr, prev); if(next == curr) return false; if(visited.find(next) != visited.end()) return true; prev = curr; curr = next; } return false; } bool isConnected(vertex_t v1, vertex_t v2) { this->DijkstraComputePaths(v1); if(min_distance[v2] != std::numeric_limits< WeightType >::infinity()) return true; return false; } vertices_set GetNodes() { return vertices; } // the 'index' of the edge will be replaced with index of a vertex std::vector GetEdges() { std::vector result; for(typename adjacency_map_t::iterator it = adjacency_map.begin(); it != adjacency_map.end(); it++) { vertex_t v1 = it->first; std::list adj = it->second; for(typename std::list::iterator i = adj.begin(); i != adj.end(); i++) { Edge e = *i; result.push_back(Edge(Min(e.target, v1), e.weight, Max(e.target, v1))); } } return result; } EdgesSet GetEdgesSet() { std::vector allEdges = GetEdges(); EdgesSet result; for(typename std::vector::iterator it = allEdges.begin(); it != allEdges.end(); it++) result.insert(*it); return result; } std::vector GetLeaves() const { std::vector leaves; for(typename adjacency_map_t::const_iterator it = adjacency_map.begin(); it != adjacency_map.end(); it++) { if(it->second.size() < 2) leaves.push_back(it->first); } return leaves; } void explore(vertex_t seed, std::set & explored) { std::queue q; q.push(seed); explored.insert(seed); while(!q.empty()) { vertex_t i = q.front(); q.pop(); std::list * adj = &adjacency_map[i]; for(typename std::list::const_iterator it = adj->begin(); it != adj->end(); it++) { vertex_t j = it->target; // Check: not visited if(explored.find(j) == explored.end()) { explored.insert(j); q.push(j); } } } } vertex_t getNodeLargestConnected() { std::vector< std::set > connectedComponents; std::set unvisited; if(vertices.size() == 0) return -1; // fill unvisited set for(typename vertices_set::const_iterator it = vertices.begin(); it != vertices.end(); it++) unvisited.insert(*it); while(unvisited.size() > 1) { // Take first unvisited node vertex_t firstNode = *(unvisited.begin()); // Explore its tree std::set currVisit; currVisit.insert(firstNode); explore(firstNode, currVisit); // Add as a connected component connectedComponents.push_back(currVisit); // Remove from unvisited set for(typename std::set::iterator it = currVisit.begin(); it != currVisit.end(); it++) unvisited.erase(*it); } // Find set with maximum number of nodes int maxConnectSize = -1, max_i = 0; for(int i = 0; i < (int)connectedComponents.size(); i++) { int currSize = connectedComponents[i].size(); if(currSize > maxConnectSize){ maxConnectSize = currSize; max_i = i; } } // Return first node of that maximum set return *(connectedComponents[max_i].begin()); } std::set GetLargestConnectedComponent() { std::vector > connectedComponents; std::set unvisited; // fill unvisited set for(typename vertices_set::const_iterator it = vertices.begin(); it != vertices.end(); it++) unvisited.insert(*it); while(unvisited.size() > 1) { // Take first unvisited node vertex_t firstNode = *(unvisited.begin()); // Explore its tree std::set currVisit; currVisit.insert(firstNode); explore(firstNode, currVisit); // Add as a connected component connectedComponents.push_back(currVisit); // Remove from unvisited set for(typename std::set::iterator it = currVisit.begin(); it != currVisit.end(); it++) unvisited.erase(*it); } // Find set with maximum number of nodes int maxConnectSize = -1, max_i = 0; for(int i = 0; i < (int)connectedComponents.size(); i++) { int currSize = connectedComponents[i].size(); if(currSize > maxConnectSize){ maxConnectSize = currSize; max_i = i; } } // Return first node of that maximum set return connectedComponents[max_i]; } void subGraph(Graph & g, const std::set & explored) { for(typename std::set::const_iterator vi = explored.begin(); vi != explored.end(); vi++) { std::list adj = g.adjacency_map[*vi]; for(typename std::list::iterator e = adj.begin(); e != adj.end(); e++) this->AddEdge(*vi, e->target, e->weight); } } std::vector< Graph > toConnectedParts() { std::vector< Graph > result; // Make a 'bitmap' of visited nodes std::map isVisited; for(typename std::set::iterator it = vertices.begin(); it != vertices.end(); it++) isVisited[*it] = false; for(typename std::map::iterator i = isVisited.begin(); i != isVisited.end(); i++) { // Check if visited if(i->second) continue; vertex_t seed = i->first; std::set explored; explore(seed, explored); // Add this new connected sub graph from exploration result.push_back(Graph()); result.back().subGraph(*this, explored); // mark as visited the explored for(typename std::set::iterator vi = explored.begin(); vi != explored.end(); vi++) isVisited[*vi] = true; } return result; } std::list GetLargestConnectedPath() { std::list longestPath; std::set seedSet = GetLargestConnectedComponent(); std::vector leaves = GetLeaves(); if(!leaves.size()) { leaves.push_back(*this->vertices.begin()); } vertex_t seed = leaves.front(); DijkstraComputePaths(seed); for(typename std::set::iterator it = seedSet.begin(); it != seedSet.end(); it++) { std::list curPath = DijkstraGetShortestPathTo(*it); if(curPath.size() > longestPath.size()) longestPath = curPath; } return longestPath; } bool CheckAdjacent(vertex_t v1, vertex_t v2) { if(v1 == v2) return true; for(typename std::list::iterator e = adjacency_map[v1].begin(); e != adjacency_map[v1].end(); e++) if(e->target == v2) return true; return false; } }; #endif // GRAPH_H