diff --git a/YASI_12/alg.graph.h b/YASI_12/alg.graph.h index 6368109..1361b83 100644 --- a/YASI_12/alg.graph.h +++ b/YASI_12/alg.graph.h @@ -8,10 +8,16 @@ namespace yasi{ namespace alg{ namespace graph{ + using namespace ds; - + ///////////////////////////////////// + // BFS algorithm + // Child classes must override default (empty) visit functions + //////////////////////////////////// template // graph class BFS{ + ////////////// enable testing ////////////// + friend class BSFTest; public: typedef typename G::VertexType VertexType; typedef typename G::EdgeType EdgeType; @@ -25,39 +31,42 @@ namespace graph{ VERTEX_VISITING, VERTEX_VISITED }; - const G& g; // the BFS ordering of vertices int* pBfsParent; - void clear(){ - } - public: - BFS(const G& g):g(g){ - pBfsParent = new int[g.numVertices()]; - } - virtual ~BFS(){ - DELETE_ARR_SAFE(pBfsParent); - } /////////////////////////////////////////////////// // override thesse function in child classes // for your own BSF visit action - virtual void visitVertexBeforeSniffingNeighbors(VertexType* v){ + virtual void visitVertexBeforeSchedulingNeighbors(VertexType* v){ // do nothing } - virtual void visitVertexAfterSniffingNeighbors(VertexType* v){ + virtual void visitVertexAfterSchedulingNeighbors(VertexType* v){ // do nothing } virtual void visitEdge(EdgeType* e){ // do nothing } ////////////////////////////////////////////////// + void clear(){ + DELETE_ARR_SAFE(pBfsParent); + } + public: + BFS(){ + } + virtual ~BFS(){ + clear(); + } // perform bfs // the BFS tree is saved in BFS::pVertexSequence // the vertex id's must be in the range [0..n-1] - void search(const G& g, const VertexType* src) const{ - // init + void search(const G& g, VertexType* src) { + // global init + clear(); int n = g.numVertices(); + pBfsParent = new int[n]; // record BFS tree + + // init const int srcId = src->id; DoublyLinkedList q; @@ -76,41 +85,178 @@ namespace graph{ // the traversal while (!q.empty()){ - VertexType* currentVertex = q.popFront(); + // pop next candidate vertex from queue + VertexType* currentVertex = q.front(); + q.popFront(); int currentId = currentVertex->id; // visit currentVertex vertexStatus[currentId] = VERTEX_VISITING; - visitVertexBeforeSniffingNeighbors(currentVertex); + ////////////////////////////////////////////////////////// + visitVertexBeforeSchedulingNeighbors(currentVertex); + ////////////////////////////////////////////////////////// - for (EdgeIterator i = v->pOutEdges->begin(); i != v->pOutEdges->end(); i++){ + for (EdgeIterator i = currentVertex->pOutEdges->begin(); i != currentVertex->pOutEdges->end(); i++){ EdgeType* e = *i; // process this edge + ////////////////////////////////////////////////////////// visitEdge(e); - + ////////////////////////////////////////////////////////// + VertexType* neighborVertex = e->end; int neighborId = neighborVertex->id; if (vertexStatus[neighborId] == VERTEX_UNDISCOVERED){ // schedule a visit to the neighbor - vertexStatus[neighborid] == VERTEX_DISCOVERED; - pBfsParent[neighborVertex] = currentVertex; + vertexStatus[neighborId] == VERTEX_DISCOVERED; + pBfsParent[neighborId] = currentId; q.pushBack(neighborVertex); } } // done visiting current vertex - visitVertexAfterSniffingNeighbors(currentVertex); + ////////////////////////////////////////////////////////// + visitVertexAfterSchedulingNeighbors(currentVertex); + ////////////////////////////////////////////////////////// vertexStatus[currentId] = VERTEX_VISITED; } // cleanup - DELETE_SAFE_ARR(vertexVisited); + DELETE_ARR_SAFE(vertexStatus); } }; + + + class BFSTest : public Test { + typedef Graph G; + typedef G::VertexType VertexType; + + template + class MyBFS : public BFS < G > { + protected: + typedef BFS parent; + typedef typename parent::VertexType VertexType; + typedef typename parent::EdgeType EdgeType; + + stringstream visitSequence; + public: + MyBFS() : parent(){ + } + virtual ~MyBFS(){ + + } + /////////// override specific visit functions ////// + virtual void visitVertexBeforeScheudlingNeighbors(VertexType* pVertex){ + visitSequence << pVertex->label << " "; + } + string getVisitSequence() const{ + return visitSequence.str(); + } + }; + + + public: + void simpleGraphs(){ + + { + SCOPED_TRACE("path"); + string strPath = + "1 2 0.5\n" + "2 3 0.5\n" + "3 4 0.5\n" + "4 5 0.5\n" + ; + G g; + g.loadFromString(strPath); + string expectedVisitSequence = "1 2 3 4 5 "; + + MyBFS bfs; + VertexType* src = *(g.getVertexList()->begin()); + bfs.search(g, src); + string actualVisitSequence = bfs.getVisitSequence(); + ASSERT_EQ(expectedVisitSequence, actualVisitSequence); + } + { + SCOPED_TRACE("binary tree"); + string strBalancedBinaryTree = + "1 2 0.5\n" + "1 3 0.5\n" + "2 4 0.5\n" + "2 5 0.5\n" + "3 6 0.5\n" + "3 7 0.5\n" + ; + G g; + g.loadFromString(strBalancedBinaryTree); + string expectedVisitSequence = "1 2 3 4 5 6 7 "; + + MyBFS bfs; + VertexType* src = *(g.getVertexList()->begin()); + bfs.search(g, src); + string actualVisitSequence = bfs.getVisitSequence(); + ASSERT_EQ(expectedVisitSequence, actualVisitSequence); + } + + { + SCOPED_TRACE("cycle"); + string strCycle = + "1 2 0.5\n" + "2 3 0.5\n" + "3 4 0.5\n" + "4 1 0.5\n" + ; + G g; + g.loadFromString(strCycle); + string expectedVisitSequence = "1 2 3 4 "; + + MyBFS bfs; + VertexType* src = *(g.getVertexList()->begin()); + bfs.search(g, src); + string actualVisitSequence = bfs.getVisitSequence(); + ASSERT_EQ(expectedVisitSequence, actualVisitSequence); + } + { + SCOPED_TRACE("complete graph K5"); + string strK5 = + "1 5 0.5\n" + "1 2 0.5\n" + "1 4 0.5\n" + "1 3 0.5\n" + "2 1 0.5\n" + "2 3 0.5\n" + "2 4 0.5\n" + "2 5 0.5\n" + "3 2 0.5\n" + "3 1 0.5\n" + "3 4 0.5\n" + "3 5 0.5\n" + "4 2 0.5\n" + "4 3 0.5\n" + "4 1 0.5\n" + "4 5 0.5\n" + "5 2 0.5\n" + "5 3 0.5\n" + "5 4 0.5\n" + "5 1 0.5\n" + ; + G g; + g.loadFromString(strK5); + string expectedVisitSequence = "1 5 2 4 3 "; + + MyBFS bfs; + VertexType* src = *(g.getVertexList()->begin()); + bfs.search(g, src); + string actualVisitSequence = bfs.getVisitSequence(); + ASSERT_EQ(expectedVisitSequence, actualVisitSequence); + } + } + }; + + ADD_TEST_F(BFSTest, simpleGraphs); + } // namespace graph } } \ No newline at end of file diff --git a/YASI_12/ds.graph.h b/YASI_12/ds.graph.h index e628cb5..8669ef3 100644 --- a/YASI_12/ds.graph.h +++ b/YASI_12/ds.graph.h @@ -84,7 +84,8 @@ class Graph : public IGraph{ edgeList.clear(); } public: - Graph(bool weighted = true) :_weighted(weighted), _vertexId(0){ + // by default, unweighted directed graph + Graph(bool weighted = false) :_weighted(weighted), _vertexId(0){ } virtual ~Graph(){ clear(); @@ -116,7 +117,12 @@ class Graph : public IGraph{ VertexList* neighbors(const VertexType* v) const{ return } - + VertexList* getVertexList(){ + return &vertexList; + } + EdgeList* getEdgeList(){ + return &edgeList; + } // strEdgeList contains non-empty lines // one line for each edge // line format: vid1 vid2 weight diff --git a/gtest-1.7.0/msvc/gtest/gtest.tlog/gtest.lastbuildstate b/gtest-1.7.0/msvc/gtest/gtest.tlog/gtest.lastbuildstate index 3c41187..2520c8c 100644 --- a/gtest-1.7.0/msvc/gtest/gtest.tlog/gtest.lastbuildstate +++ b/gtest-1.7.0/msvc/gtest/gtest.tlog/gtest.lastbuildstate @@ -1,2 +1,2 @@ #TargetFrameworkVersion=v4.0:PlatformToolSet=v120:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit -Debug|Win32|C:\Saad\Dropbox\Projects\C++\SimilarKinases\| +Debug|Win32|C:\Saad\Dropbox\Projects\C++\YASI\|