#ifndef GRAPH_H_ #define GRAPH_H_ #include "../chp2/Vector.h" #include "../chp4/Stack.h" #include "../chp4/Queue.h" typedef enum { UNDISCOVERED, DISCOVERED, VISITED } VStatus; typedef enum { UNDETERMINED, TREE, BACKWARD, FORWARD, CROSS } Etype; //abstract class Graph template class Graph{ private: void reset(); //reset all information of all vertices and edges void BFS(int, int&); //Breadth First Search void DFS(int, int&); //Depth First Search void BCC(int, int&, Stack&); //Biconnected Component bool TSort(int, int&, Stack*); //Topological Sort template void PFS(int, PU); //Priority First Search public: int num_of_vertices; int num_of_edges; //vertex methods virtual int insertVertex(Tv const&) = 0; //return the id number of the new vertex virtual Tv removeVertex(int) = 0; virtual Tv& vertex(int) = 0; virtual int inDegree(int) = 0; virtual int outDegree(int) = 0; virtual int firstNeighbor(int) = 0; virtual int nextNeighbor(int, int) = 0; virtual int& dtime(int) = 0; virtual int& ftime(int) = 0; virtual int& parent(int) = 0; virtual int& priority(int) = 0; virtual VStatus& status(int) = 0; //directed egde methods virtual bool exists(int, int) = 0; virtual void insertEdge(Te const&, double, int, int) = 0; virtual Te removeEdge(int, int) = 0; virtual Etype& type(int, int) = 0; virtual Te& edge(int, int) = 0; virtual double& weight(int, int) = 0; //Graph related algorithms void bfs(int); void dfs(int); void bcc(int); void prim(int); void dijkstra(int); Stack* tSort(int); template void pfs(int, PU); }; //private methods template void Graph::reset(){//reset all information of all vertices and edges for(int ix = 0; ix != num_of_vertices; ++ix){ status(ix) = UNDISCOVERED; priority(ix) = INT_MAX; dtime(ix) = -1; ftime(ix) = -1; parent(ix) = -1; for (int jx = 0; jx != num_of_vertices; ++jx) if(exists(ix, jx)) type(ix, jx) = UNDETERMINED; } } template void Graph::BFS(int x, int &clock){ Queue Q; int neighbor; Q.enqueue(x); status(x) = DISCOVERED; while(!Q.empty()){ x = Q.dequeue(); dtime(x) = ++clock; for (neighbor = firstNeighbor(x); neighbor != -1; neighbor = nextNeighbor(x, neighbor)){ if (status(neighbor) == UNDISCOVERED) { status(neighbor) = DISCOVERED; type(x, neighbor) = TREE; parent(neighbor) = x; Q.enqueue(neighbor); } else type(x, neighbor) = CROSS; } status(x) = VISITED; } } template void Graph::DFS(int x, int& clock){ dtime(x) = ++clock; status(x) = DISCOVERED; for(int neighbor = firstNeighbor(x); neighbor != -1; neighbor = nextNeighbor(x, neighbor)){ switch(status(neighbor)){ case UNDISCOVERED: type(x, neighbor) = TREE; parent(neighbor) = x; DFS(neighbor, clock); break; case DISCOVERED: type(x, neighbor) = BACKWARD; break; case VISITED: default: if (dtime(x) < dtime(neighbor)) type(x, neighbor) = FORWARD; else type(x, neighbor) = CROSS; break; } } ftime(x) = ++clock; status(x) = VISITED; } #define hca(x) ftime(x) template void Graph::BCC(int x, int &clock, Stack &S) { status(x) = DISCOVERED; S.push(x); hca(x) = dtime(x) = ++clock; for (int v = firstNeighbor(x); v != -1; v = nextNeighbor(x, v)) { switch (status(v)) { case UNDISCOVERED: type(x, v) = TREE; BCC(v, clock, S); if (hca(v) < dtime(x)) hca(x) = MIN(hca(v), hca(x)); else {//a biconnected component found while (S.pop() != x); S.push(x); } break; case DISCOVERED: type(x, v) = BACKWARD; if (parent(x) != v) hca(x) = MIN(hca(x), dtime(v)); break; case VISITED: default: type(x, v) = dtime(x) < dtime(v) ? FORWARD : CROSS; break; } } } #undef hca template bool Graph::TSort(int x, int &clock, Stack *S){ status(x) = DISCOVERED; dtime(x) = ++clock; for(int v = firstNeighbor(x); v != -1; v = nextNeighbor(x, v)){ switch(status(v)){ case UNDISCOVERED: status(v) = DISCOVERED; type(x, v) = TREE; if (!TSort(v, clock, S)) return false; break; case DISCOVERED: type(x, v) = BACKWARD; return false; case VISITED: default: type(x, v) = dtime(x) > dtime(v)? FORWARD: CROSS; break; } } S->push(x); return true; } template template void Graph::PFS(int x, PU PrioUpdater){ priority(x) = 0; status(x) = VISITED; parent(x) = -1; while(1){ for (int v = firstNeighbor(x); v != -1; v = nextNeighbor(x, v)) PrioUpdater(this, x, v); //find current highest priority for (int shortest = INT_MAX, v = 0; v != num_of_vertices; ++v) if (status(v) == UNDISCOVERED && priority(v) < shortest) { shortest = priority(v); x = v; } if (status(x) == VISITED) break; status(x) == VISITED; type(parent(x), x) = TREE; } } //Graph related algorithms template void Graph::bfs(int start){ reset(); int x = start; int clock = 0; do { if (status(x) == UNDISCOVERED) BFS(x, clock); } while ((x = ++x % num_of_vertices) != start); } template void Graph::dfs(int start){ reset(); int clock = 0; int x = start; do{ if (status(x) == UNDISCOVERED) DFS(x, clock); } while ((x = ++x % num_of_vertices) != start); } template void Graph::bcc(int start){ reset(); int clock = 0; int curr = start; Stack S; do{ if (status(curr) == UNDISCOVERED) { BCC(curr, clock, S); S.pop(); //remove the last element in the Stack, which is the start point of current connected components } } while ((curr = ++curr % num_of_vertices) ŁĄ = start); } //Prim Algorithm template class PrimPU{ public: void operator()(Graph *G, int parent, int v){ if(G->status(v) == UNDISCOVERED){ if (G->weight(parent, v) < G->priority(v)) { G->priority = G->weight(parent, v); G->parent(v) = parent; } } } }; template void Graph::prim(int x){ pfs(x, PrimPU()); } //Dijkstra Algorithm template class DijkstraPU{ public: void operator()(Graph *G, int parent, int v){ if(G->status(v) == UNDISCOVERED){ if(G->priority(parent) + G->weight(parent, v) < G->priority(v)){ G->priority(v) = G->priority(parent) + G->weight(parent, v); G->parent(v) = parent; } } } }; template void Graph::dijkstra(int x){ pfs(x, DijkstraPU()); } template Stack* Graph::tSort(int start){ reset(); Stack *S; int clock = 0; int curr = start; do{ if(status(curr) == UNDISCOVERED && !TSort(curr, clock, S)){ while (!S->empty()) S->pop(); break; } } while ((curr = ++curr % num_of_vertices) != start); return S; } template template void Graph::pfs(int start, PU PrioUpdater){ reset(); int curr = start; do{ if (status(curr) == UNDISCOVERED) PFS(curr, PrioUpdater); } while ((curr = ++curr % num_of_vertices) != start); } #endif