/***************************************************************************** Copyright (C) 2008 University of Southern California Copyright (C) 2010 University of Utah All Rights Reserved. Purpose: Graph template class supports topological sort with return result observing strongly connected component. Notes: The result of topologically sorting a graph V={1,2,3,4} and E={1->2, 1->3, 2->3, 3->2, 3->4} is ({1}, {2,3}, {4}). History: 01/2006 Created by Chun Chen. 07/2010 add a new topological order, -chun *****************************************************************************/ #ifndef GRAPH_HH #define GRAPH_HH #include #include #include #include #include #include #include struct Empty { Empty() {}; bool operator<(const Empty &) const { return true; }; bool operator==(const Empty &) const { return false; }; friend std::ostream& operator<<(std::ostream &os, const Empty &) { return os; }; }; namespace { enum GraphColorType {WHITE, GREY, BLACK}; } template struct Graph; template std::ostream& operator<<(std::ostream &os, const Graph &g); template struct Graph { typedef std::map > EdgeList; typedef std::vector > VertexList; VertexList vertex; bool directed; Graph(bool directed = true); int vertexCount() const; int edgeCount() const; bool isEmpty() const; bool isDirected() const; int insert(const VertexType &v = VertexType()); void connect(int v1, int v2, const EdgeType &e = EdgeType()); void connect(int v1, int v2, const std::vector &e); void disconnect(int v1, int v2); bool hasEdge(int v1, int v2) const; std::vector getEdge(int v1, int v2) const; std::vector > topoSort() const; std::vector > packed_topoSort() const; void dump() { std::cout << *this; } friend std::ostream& operator<< <>(std::ostream &os, const Graph &g); }; template std::ostream& operator<<(std::ostream &os, const Graph &g) { for (int i = 0; i < g.vertex.size(); i++) for (typename Graph::EdgeList::const_iterator j = g.vertex[i].second.begin(); j != g.vertex[i].second.end(); j++) { // os << i+1 << "->" << j->first+1 << ":"; os << "s" << i << "->" << "s" << j->first << ":"; for (typename std::vector::const_iterator k = j->second.begin(); k != j->second.end(); k++) os << " " << *k; os << std::endl; } return os; } template Graph::Graph(bool directed_): directed(directed_) { } template int Graph::vertexCount() const { return vertex.size(); } template int Graph::edgeCount() const { int result = 0; for (int i = 0; i < vertex.size(); i++) for (typename EdgeList::const_iterator j = vertex[i].second.begin(); j != vertex[i].second.end(); j++) result += j->second.size(); if (!directed) result = result/2; return result; } template bool Graph::isEmpty() const { return vertex.size() == 0; } template bool Graph::isDirected() const { return directed; } template int Graph::insert(const VertexType & v) { for (int i = 0; i < vertex.size(); i++) if (vertex[i].first == v) return i; vertex.push_back(std::make_pair(v, EdgeList())); return vertex.size() - 1; } template void Graph::connect(int v1, int v2, const EdgeType &e) { assert(v1 < vertex.size() && v2 < vertex.size()); vertex[v1].second[v2].push_back(e);; if (!directed) vertex[v2].second[v1].push_back(e); } template void Graph::connect(int v1, int v2, const std::vector &e) { assert(v1 < vertex.size() && v2 < vertex.size()); if (e.size() == 0) return; copy(e.begin(), e.end(), back_inserter(vertex[v1].second[v2])); if (!directed) copy(e.begin(), e.end(), back_inserter(vertex[v2].second[v1])); } template void Graph::disconnect(int v1, int v2) { assert(v1 < vertex.size() && v2 < vertex.size()); vertex[v1].second.erase(v2); if (!directed) vertex[v2].second.erase(v1); } template bool Graph::hasEdge(int v1, int v2) const { return vertex[v1].second.find(v2) != vertex[v1].second.end(); } template std::vector Graph::getEdge(int v1, int v2) const { if (!hasEdge(v1, v2)) return std::vector(); return vertex[v1].second.find(v2)->second; } // This topological sort does handle SCC in graph. template std::vector > Graph::topoSort() const { const int n = vertex.size(); std::vector color(n, WHITE); std::stack S; std::vector order(n); int c = n; // first DFS for (int i = n-1; i >= 0; i--) if (color[i] == WHITE) { S.push(i); while (!S.empty()) { int v = S.top(); if (color[v] == WHITE) { for (typename EdgeList::const_iterator j = vertex[v].second.begin(); j != vertex[v].second.end(); j++) if (color[j->first] == WHITE) S.push(j->first); color[v] = GREY; } else if (color[v] == GREY) { color[v] = BLACK; S.pop(); order[--c] = v; } else { S.pop(); } } } // transpose edge std::vector > edgeT(n); for (int i = 0; i < n; i++) for (typename EdgeList::const_iterator j = vertex[i].second.begin(); j != vertex[i].second.end(); j++) edgeT[j->first].insert(i); // second DFS in transposed graph starting from last finished vertex fill(color.begin(), color.end(), WHITE); std::vector > result; for (int i = 0; i < n; i++) if (color[order[i]] == WHITE) { std::set s; S.push(order[i]); while (!S.empty()) { int v = S.top(); if(color[v] == WHITE) { for (std::set::const_iterator j = edgeT[v].begin(); j != edgeT[v].end(); j++) if (color[*j] == WHITE) S.push(*j); color[v] = GREY; } else if (color[v] == GREY) { color[v] = BLACK; S.pop(); s.insert(v); } else { S.pop(); } } result.push_back(s); } return result; } // This topological sort does not handle SCC in graph. template std::vector > Graph::packed_topoSort() const { const int n = vertex.size(); std::vector color(n, WHITE); std::stack S; std::vector is_root(n, false); std::vector > edges(n); // first DFS for (int i = n-1; i >= 0; i--) if (color[i] == WHITE) { S.push(i); is_root[i] = true; while (!S.empty()) { int v = S.top(); if (color[v] == WHITE) { for (typename EdgeList::const_iterator j = vertex[v].second.begin(); j != vertex[v].second.end(); j++) if (color[j->first] == WHITE) { S.push(j->first); edges[v].insert(j->first); } else if (color[j->first] == BLACK) { if (is_root[j->first]) { is_root[j->first] = false; edges[v].insert(j->first); } } color[v] = GREY; } else if (color[v] == GREY) { color[v] = BLACK; S.pop(); } else { S.pop(); } } } // second BFS in DFS tree starting from roots std::vector > result; std::set s; for (int i = 0; i < n; i++) if (is_root[i]) s.insert(i); if (s.size() != 0) { result.push_back(s); while (true) { std::set s; for (std::set::iterator i = result[result.size()-1].begin(); i != result[result.size()-1].end(); i++) s.insert(edges[*i].begin(), edges[*i].end()); if (s.size() != 0) result.push_back(s); else break; } } return result; } #endif