Skip to content

Commit

Permalink
Added BFS class.
Browse files Browse the repository at this point in the history
Todo: testing

Signed-off-by: unknown <saq10002@iteb-219.ad.engr.uconn.edu>
  • Loading branch information
unknown committed Sep 23, 2014
1 parent b902e11 commit f75b407
Show file tree
Hide file tree
Showing 2 changed files with 200 additions and 13 deletions.
116 changes: 116 additions & 0 deletions YASI_12/alg.graph.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#pragma once
#include "common.h"
#include "ds.graph.h"
#include "ds.doublylinkedlist.h"
using namespace std;

namespace yasi{
namespace alg{

namespace graph{


template<class G> // graph
class BFS{
public:
typedef typename G::VertexType VertexType;
typedef typename G::EdgeType EdgeType;
typedef typename G::VertexIterator VertexIterator;
typedef typename G::EdgeIterator EdgeIterator;
typedef typename G::VertexList VertexList;
protected:
enum {
VERTEX_UNDISCOVERED = 0,
VERTEX_DISCOVERED,
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){
// do nothing
}
virtual void visitVertexAfterSniffingNeighbors(VertexType* v){
// do nothing
}
virtual void visitEdge(EdgeType* e){
// do nothing
}
//////////////////////////////////////////////////

// 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
int n = g.numVertices();
const int srcId = src->id;
DoublyLinkedList<VertexType*> q;

int* vertexStatus = new int[n];
for (int i = 0; i < n; i++){
if (i == srcId) continue;
vertexStatus[i] = VERTEX_UNDISCOVERED;
// parent of each vertex in BFS tree is initially NULL
pBfsParent[i] = -1;
}

// the source vertex
vertexStatus[srcId] = VERTEX_DISCOVERED;
pBfsParent[srcId] = -1;
q.pushBack(src);

// the traversal
while (!q.empty()){
VertexType* currentVertex = q.popFront();
int currentId = currentVertex->id;

// visit currentVertex
vertexStatus[currentId] = VERTEX_VISITING;
visitVertexBeforeSniffingNeighbors(currentVertex);

for (EdgeIterator i = v->pOutEdges->begin(); i != v->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;
q.pushBack(neighborVertex);
}

}

// done visiting current vertex
visitVertexAfterSniffingNeighbors(currentVertex);
vertexStatus[currentId] = VERTEX_VISITED;

}

// cleanup
DELETE_SAFE_ARR(vertexVisited);
}

};

} // namespace graph
}
}
97 changes: 84 additions & 13 deletions YASI_12/ds.graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ using namespace std;
namespace yasi{
namespace ds{

// forward declarations
class VertexBase;
class EdgeBase;

template<class V, class Element>
struct Edge{
Element element;
Expand All @@ -29,8 +25,11 @@ struct Vertex{
typedef Edge<self, EdgeElement> edge;
public:
typedef DoublyLinkedList< edge* > EdgeList;
int id;
Element element;

int id; // id assigned by the graph data structure
int label; // label assigned with input description
Element element; // possibly composite information stored at this vertex

EdgeList* pInEdges;
EdgeList* pOutEdges;

Expand Down Expand Up @@ -63,12 +62,18 @@ class Graph : public IGraph{
typedef Edge<VertexType, EdgeElement> EdgeType;
typedef DoublyLinkedList<VertexType*> VertexList;
typedef DoublyLinkedList<EdgeType*> EdgeList;
typedef VertexList::iterator VertexIterator;
typedef EdgeList::iterator EdgeIterator;
protected:
VertexList vertexList;
EdgeList edgeList;
const bool _weighted;

// this is the id of the next vertex
int _vertexId;

void clear(){
_vertexId = 0;
for (VertexList::iterator i = vertexList.begin(); i != vertexList.end(); i++){
DELETE_SAFE(*i);
}
Expand All @@ -79,9 +84,10 @@ class Graph : public IGraph{
edgeList.clear();
}
public:
Graph(bool weighted = true) :_weighted(weighted){
Graph(bool weighted = true) :_weighted(weighted), _vertexId(0){
}
virtual ~Graph(){
clear();
}
int numVertices() const override{
return vertexList.size();
Expand All @@ -96,28 +102,46 @@ class Graph : public IGraph{
v2->pInEdges->pushBack(edge);
return edge;
}
VertexType* addVertex(int id){
VertexType* pVertex = new VertexType(id);
VertexType* addVertex(int label){
VertexType* pVertex = new VertexType(_vertexId++);
pVertex->label = label;
vertexList.pushBack(pVertex);
return pVertex;
}
VertexType* addVertex(int id, VertexElement e){
VertexType* addVertex(int label, VertexElement e){
VertexType* pVertex = addVertex(id);
pVertex->element = e;
return pVertex;
}
VertexList* neighbors(const VertexType* v) const{
return
}

// strEdgeList contains non-empty lines
// one line for each edge
// line format: vid1 vid2 weight
void loadFromString(string strEdgeList){
clear();
// cleanup the input string of all '\r' and flanking '\r\n'
strEdgeList = strPurge(strEdgeList, "\r");
stringstream inp(trim(strEdgeList));
// comments char
string commentChars = ";#";

// use a temporary hashtable
IntLinearProbingHashTable< VertexType* > ht;

while (! inp.eof()){
// comment line
char leadingChar = inp.peek();
if (commentChars.find(leadingChar) != string::npos ||// comment
leadingChar == '\n'){ // empty line
// skip this comment line
inp.ignore(INT_MAX, '\n');
continue;
}


int vid1, vid2;
float w;
// vertices
Expand All @@ -139,7 +163,7 @@ class Graph : public IGraph{
ppv1 = ht.get(vid1);
if (!ppv1){
pv1 = addVertex(vid1);
ht.put(vid1, pv1);
ht.put(vertexId, pv1);
}
else{
pv1 = *ppv1;
Expand All @@ -156,24 +180,71 @@ class Graph : public IGraph{
// create edge
addEdge(pv1, pv2, w);
}


}

string toString(){
stringstream str;
str << "; Number of vertices" << endl << numVertices() << endl
<< "; Number of edges" << endl << numEdges() << endl;
str << "; List of edges" << endl;
for (VertexList::iterator i = vertexList.begin(); i != vertexList.end(); i++){
// for each vertex
VertexType* v = *i;
for (EdgeList::iterator j = v->pOutEdges->begin(); j != v->pOutEdges->end(); j++){
// for each outgoing edge
EdgeType* e = *j;
str << e->start->id << " " << e->end->id;
if (_weighted){
str << " " << e->weight;
}
str << endl;
}
}
return str.str();
}
}; // class Graph

template<class V, class E>
ostream& operator<<(ostream& out, const Graph<V, E>& g){ out << g.toString(); return out; }

class GraphTest : public yasi::Test{
public:
void loadFromString(){
Graph<int> g;
typedef Graph<int>::VertexIterator VertexIterator;

// simple triangle
string triangle =
string triangle =
"; this is comment\n"
"1 2 12\n"
"1 3 13\n"
"2 3 23\n";
"\n"
"; some other comments\n"
"2 3 23\n"
"; finishing comments";
const string strTriangle =
"; Number of vertices\n"
"3\n"
"; Number of edges\n"
"3\n"
"; List of edges\n"
"1 2 12\n"
"1 3 13\n"
"2 3 23\n"
;
g.loadFromString(triangle);

// test
ASSERT_EQ(3, g.numVertices());
ASSERT_EQ(3, g.numEdges());
// now make sure that all id's are different, and they are in the range [1..n-1]
for (VertexIterator i = g.vertexList.begin(); i != g.vertexList.end(); i++){
ASSERT_LE(0, (*i)->id);
ASSERT_GT(g.numVertices(), (*i)->id);
}
ASSERT_EQ(strTriangle, g.toString());
}

};
Expand Down

0 comments on commit f75b407

Please sign in to comment.